Archiwum kategorii: CSS

Getting Nowhere on Job Titles

Post pobrano z: Getting Nowhere on Job Titles

Last week on ShopTalk, Dave and I spoke with Mandy Michael and Lara Schenck. Mandy had just written the intentionally provocative „Is there any value in people who cannot write JavaScript?” which guided our conversation. Lara is deeply interested in this subject as well, as someone who is a job seeking web worker, but places herself on the spectrum as a non-unicorn.

Part of that discussion was about job titles. If there was a ubiquitously accepted and used job title that meant you were specifically skilled at HTML and CSS, and there was a market for that job title, there probably wouldn’t be any problem at all. There isn’t though. „Web developer” is too vague. „Front-end developer” maybe used to mean that, but has been largely co-opted by JavaScript.

In fact, you might say that none of us has an exactly perfect job title and the industry at large has trouble agreeing on a set of job titles.

Lara created a repo with the intent to think all this out and discuss it.

If there is already a spectrum between design and backend development, and front-end development is that place in between, perhaps front-end development, if we zoon in, is a spectrum as well:

I like the idea of spectrums, but I also agree with a comment by Sarah Drasner where she mentioned that this makes it seem like you can’t be good at both. If you’re a dot right in the middle in this specrum, you are, for example, not as good at JavaScript as someone on the right.

This could probably be fixed with some different dataviz (perhaps the size of the dot), or, heaven forbid, skill-level bars.

More importantly, if you’re really interested in the discussion around all this, Lara has used the issues area to open that up.

Last year, Geoff also started thinking about all our web jobs as a spectrum. We can break up our jobs into parts and map them onto those parts in differnet ways:

See the Pen Web Terminology Matrix by Geoff Graham (@geoffgraham) on CodePen.

See the Pen Web Terminology Venn Diagram by Geoff Graham (@geoffgraham) on CodePen.

That can certainly help us understand our world a little bit, but doesn’t quite help with the job titles thing. It’s unlikely we’ll get people to write job descriptions that include a data visualization of what they are looking for.

Jeff Pelletier took a crack at job titles and narrowed it down to three:

Front-end Implementation (responsive web design, modular/scalable CSS, UI frameworks, living style guides, progressive enhancement & accessibility, animation and front-end performance).

Application Development (JavaScript frameworks, JavaScript preprocessors, code quality, process automation, testing).

Front-end Operations (build tools, deployment, speed: (app, tests, builds, deploys), monitoring errors/logs, and stability).

Although those don’t quite feel like titles to me and converting them into something like „Front-end implementation developer” doesn’t seem like something that will catch on.

Cody Lindley’s Front-End Developer Handbook has a section on job titles. I won’t quote it in full, but they are:

  • Front-End Developer
  • Front-End Engineer (aka JavaScript Developer or Full-stack JavaScript Developer)
  • CSS/HTML Developer
  • Front-End Web Designer
  • Web/Front-End User Interface (aka UI) Developer/Engineer
  • Mobile/Tablet Front-End Developer
  • Front-End SEO Expert
  • Front-End Accessibility Expert
  • Front-End Dev. Ops
  • Front-End Testing/QA

Note the contentious „full stack” title, in which Brad Frost says:

In my experience, “full-stack developers” always translates to “programmers who can do frontend code because they have to and it’s ‘easy’.” It’s never the other way around.

Still, these largely feel pretty good to me. And yet weirdly, almost like there is both too many and too few. As in, while there is good coverage here, but if you are going to cover specialties, you might as well add in performance, copywriting, analytics, and more as well. The more you add, the further away we are to locking things down. Not to mention the harder it becomes when people crossover these disciplines, like they almost always do.

Oh well.


Getting Nowhere on Job Titles is a post from CSS-Tricks

I haven’t experienced imposter syndrome, and maybe you haven’t either

Post pobrano z: I haven’t experienced imposter syndrome, and maybe you haven’t either

In recent years it’s become trendy to discuss how we all apparently suffer from this imposter syndrome – an inability to internalize one’s accomplishments and a persistent fear of being exposed as a “fraud”.

I take two issues with this:

  • it minimizes the impact that this experience has on people that really do suffer from it.
  • we’re labelling what should be considered positive personality traits – humility, an acceptance that we can’t be right all the time, a desire to know more, as a “syndrome” that we need to “deal with”, “get over” or “get past”.

It’s not an officially recognized syndrome (yet?), but you can have medical diagnoses that are like imposter syndrome. A general feeling that you’re faking it or don’t know as much as you should isn’t it.

Direct Link to Article — Permalink


I haven’t experienced imposter syndrome, and maybe you haven’t either is a post from CSS-Tricks

Prettier + Stylelint: Writing Very Clean CSS (Or, Keeping Clean Code is a Two-Tool Game)

Post pobrano z: Prettier + Stylelint: Writing Very Clean CSS (Or, Keeping Clean Code is a Two-Tool Game)

It sure is nice having a whole codebase that is perfectly compliant to a set of code style guidelines. All the files use the same indentation, the same quote style, the same spacing and line-break rules, heck, tiny things like the way zero’s in values are handled and how keyframes are named.

It seems like a tall order, but these days, it’s easier than ever. It seems to me it’s become a two-tool game:

  1. A tool to automatically fix easy-to-fix problems
  2. A tool to warn about harder-to-fix problems

Half the battle: Prettier

Otherwise known as „fix things for me, please”.

Best I can tell, Prettier is a fairly new project, only busting onto the scene in January 2017. Now in the last quarter of 2017, it seems like everybody and their sister is using it. They call it an Opinionated Code Formatter.

The big idea: upon save of a document, all kinds of code formatting happens automatically. It’s a glorious thing to behold. Indentation and spacing is corrected. Quotes are consistent-ified. Semi colons are added.

Run Prettier over your codebase once and gone are the muddy commits full of code formatting cruft. (You might consider making a temporary git user so one user doesn’t look like they’ve commited a bazillion lines of code more than another, if you care about that.) That alone is a damn nice benefit. It makes looking through commits a heck of a lot easier and saves a bunch of grunt work.

As this post suggest, Prettier is only half the battle though. You’ll notice that Prettier only supports a handful of options. In fact, I’m pretty sure when it launched it didn’t have any configuration at all. Opinionated indeed.

What it does support are things that are easy to fix, requiring zero human brainpower. Use double quotes accidentally (uggkch muscle memory) when your style guide is single quotes? Boom – changed on save.

There are other potential problems that aren’t as easy to fix. For example, you’ve used an invalid #HEX code. You probably wouldn’t want a computer guessing what you meant there. That’s better to just be visually marked as an error for you to fix.

That’s where this next part comes in.

The other half of the battle: Stylelint

Otherwise known as „let me know about problem, so I can fix them”.

Stylelint is exactly that. In fact, in that GIF above show Prettier do it’s thing, you saw some red dots and red outlines in my Sublime Text editor. That wasn’t Prettier showing me what it was going to fix (Prettier displays no errors, it just fixes what it can). That was Stylelint running it’s linting and showing me those errors.

Whereas Prettier supports 10ish rules, Stylelint supports 150ish. There is a standard configuration, but you can also get as fine-grained as you want there and configure how you please. David Clark wrote about it here on CSS-Tricks last year.

With these warnings so clearly visible, you can fix them up by hand quickly. It becomes rather second nature.

Getting it all going

These tools work in a wide variety of code editors.

These are the Prettier editor integrations. Between all these, that probably covers 96% webdevnerds.

It’s very easy to think „I’ll just install this into my code editor, and it will work!” That gets me every time. Getting these tools to work is again a two-part game.

  1. Install code editor plugin.
  2. Do the npm / yarn installation stuff. These are node-based tools. It doesn’t mean your project needs to have anything to do with node in production, this is a local development dependency.

These are intentionally separated things. The meat of these tools is the code that parses your code and figures out the problems it’s going to fix. That happens through APIs that other tools can call. That means these tools don’t have to be rewritten and ported to work in a new environment, instead, that new environment calls the same APIs everyone else does and does whatever it needs to do with the results.

Above is a barebones project in Sublime Text with both Prettier and Stylelint installed. Note the `package.json` shows we have our tools installed and I’m listing my „packages” so you can see I have the Sublime Text Plugin jsPrettier installed. You can also see the dotfiles there that configure the rules for both tools.

Don’t let the „js” part mislead you. You could use this setup on the CSS of your WordPress site. It really doesn’t matter what your project is.

Getting more exotic

There is certainly leveling up that can happen here. For example:

  • You might consider configuring Stylelint to ignore problems that Prettier fixes. They are going to be fixed anyway, so why bother looking at the errors.
  • You might consider updating your deployment process to stop if Stylelint problems are found. Sometimes Stylelint is showing you an error that will literally cause a problem, so it really shouldn’t go to production.
  • We mostly talked about CSS here, but JavaScript is arguably even more important to lint (and Prettier supports as well). ES Lint is probably the way to go here. There are also tools like Rubocop for Ruby, and I’m sure linters for about every language imaginable.

Related


Prettier + Stylelint: Writing Very Clean CSS (Or, Keeping Clean Code is a Two-Tool Game) is a post from CSS-Tricks

Building a Progress Ring, Quickly

Post pobrano z: Building a Progress Ring, Quickly

On some particularly heavy sites, the user needs to see a visual cue temporarily to indicate that resources and assets are still loading before they taking in a finished site. There are different kinds of approaches to solving for this kind of UX, from spinners to skeleton screens.

If we are using an out-of-the-box solution that provides us the current progress, like preloader package by Jam3 does, building a loading indicator becomes easier.

For this, we will make a ring/circle, style it, animate given a progress, and then wrap it in a component for development use.

Step 1: Let’s make an SVG ring

From the many ways available to draw a circle using just HTML and CSS, I’m choosing SVG since it’s possible to configure and style through attributes while preserving its resolution in all screens.

<svg
  class="progress-ring"
  height="120"
  width="120"
>
  <circle
    class="progress-ring__circle"
    stroke-width="1"
    fill="transparent"
    r="58"
    cx="60"
    cy="60"
  />
</svg>

Inside an <svg> element we place a <circle> tag, where we declare the radius of the ring with the r attribute, its position from the center in the SVG viewBox with cx and cy and the width of the circle stroke.

You might have noticed the radius is 58 and not 60 which would seem correct. We need to subtract the stroke or the circle will overflow the SVG wrapper.

radius = (width / 2) - (strokeWidth * 2)

These means that if we increase the stroke to 4, then the radius should be 52.

52 = (120 / 2) - (4 * 2)

So it looks like a ring we need to set its fill to transparent and choose a stroke color for the circle.

See the Pen SVG ring by Jeremias Menichelli (@jeremenichelli) on CodePen.

Step 2: Adding the stroke

The next step is to animate the length of the outer line of our ring to simulate visual progress.

We are going to use two CSS properties that you might not have heard of before since they are exclusive to SVG elements, stroke-dasharray and stroke-dashoffset.

stroke-dasharray

This property is like border-style: dashed but it lets you define the width of the dashes and the gap between them.

.progress-ring__circle {
  stroke-dasharray: 10 20;
}

With those values, our ring will have 10px dashes separated by 20px.

See the Pen Dashed SVG ring by Jeremias Menichelli (@jeremenichelli) on CodePen.

stroke-dashoffset

The second one allows you to move the starting point of this dash-gap sequence along the path of the SVG element.

Now, imagine if we passed the circle’s circumference to both stroke-dasharray values. Our shape would have one long dash occupying the whole length and a gap of the same length which wouldn’t be visible.

This will cause no change initially, but if we also set to the stroke-dashoffset the same length, then the long dash will move all the way and reveal the gap.

Decreasing stroke-dasharray would start to reveal our shape.

A few years ago, Jake Archibald explained this technique in this article, which also has a live example that will help you understand it better. You should go read his tutorial.

The circumference

What we need now is that length which can be calculated with the radius and this simple trigonometric formula.

circumference = radius * 2 * PI

Since we know 52 is the radius of our ring:

326.7256 ~= 52 * 2 * PI

We could also get this value by JavaScript if we want:

const circle = document.querySelector('.progress-ring__circle');
const radius = circle.r.baseVal.value;
const circumference = radius * 2 * Math.PI;

This way we can later assign styles to our circle element.

circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = circumference;

Step 3: Progress to offset

With this little trick, we know that assigning the circumference value to stroke-dashoffset will reflect the status of zero progress and the 0 value will indicate progress is complete.

Therefore, as the progress grows we need to reduce the offset like this:

function setProgress(percent) {
  const offset = circumference - percent / 100 * circumference;
  circle.style.strokeDashoffset = offset;
}

By transitioning the property, we will get the animation feel:

.progress-ring__circle {
  transition: stroke-dashoffset 0.35s;
}

One particular thing about stroke-dashoffset: its starting point is vertically centered and horizontally titled to the right. It’s necessary to negatively rotate the circle to get the desired effect.

.progress-ring__circle {
  transition: stroke-dashoffset 0.35s;
  transform: rotate(-90deg);
  transform-origin: 50% 50%,
}

Putting all of this together will give us something like this.

See the Pen vegymB by Jeremias Menichelli (@jeremenichelli) on CodePen.

A numeric input was added in this example to help you test the animation.

For this to be easily coupled inside your application it would be best to encapsulate the solution in a component.

As a web component

Now that we have the logic, the styles, and the HTML for our loading ring we can port it easily to any technology or framework.

First, let’s use web components.

class ProgressRing extends HTMLElement {...}

window.customElements.define('progress-ring', ProgressRing);

This is the standard declaration of a custom element, extending the native HTMLElement class, which can be configured by attributes.

<progress-ring stroke="4" radius="60" progress="0"></progress-ring>

Inside the constructor of the element, we will create a shadow root to encapsulate the styles and its template.

constructor() {
  super();

  // get config from attributes
  const stroke = this.getAttribute('stroke');
  const radius = this.getAttribute('radius');
  const normalizedRadius = radius - stroke * 2;
  this._circumference = normalizedRadius * 2 * Math.PI;

  // create shadow dom root
  this._root = this.attachShadow({mode: 'open'});
  this._root.innerHTML = `
    <svg
      height="${radius * 2}"
      width="${radius * 2}"
     >
       <circle
         stroke="white"
         stroke-dasharray="${this._circumference} ${this._circumference}"
         style="stroke-dashoffset:${this._circumference}"
         stroke-width="${stroke}"
         fill="transparent"
         r="${normalizedRadius}"
         cx="${radius}"
         cy="${radius}"
      />
    </svg>

    <style>
      circle {
        transition: stroke-dashoffset 0.35s;
        transform: rotate(-90deg);
        transform-origin: 50% 50%;
      }
    </style>
  `;
}

You may have noticed that we have not hardcoded the values into our SVG, instead we are getting them from the attributes passed to the element.

Also, we are calculating the circumference of the ring and setting stroke-dasharray and stroke-dashoffset ahead of time.

The next thing is to observe the progress attribute and modify the circle styles.

setProgress(percent) {
  const offset = this._circumference - (percent / 100 * this._circumference);
  const circle = this._root.querySelector('circle');
  circle.style.strokeDashoffset = offset; 
}

static get observedAttributes() {
  return [ 'progress' ];
}

attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'progress') {
    this.setProgress(newValue);
  }
}

Here setProgress becomes a class method that will be called when the progress attribute is changed.

The observedAttributes are defined by a static getter which will trigger attributeChangeCallback when, in this case, progress is modified.

See the Pen ProgressRing web component by Jeremias Menichelli (@jeremenichelli) on CodePen.

This Pen only works in Chrome at the time of this writing. An interval was added to simulate the progress change.

As a Vue component

Web components are great. That said, some of the available libraries and frameworks, like Vue.js, can do quite a bit of the heavy-lifting.

To start, we need to define the view component.

const ProgressRing = Vue.component('progress-ring', {});

Writing a single file component is also possible and probably cleaner but we are adopting the factory syntax to match the final code demo.

We will define the attributes as props and the calculations as data.

const ProgressRing = Vue.component('progress-ring', {
  props: {
    radius: Number,
    progress: Number,
    stroke: Number
  },
  data() {
    const normalizedRadius = this.radius - this.stroke * 2;
    const circumference = normalizedRadius * 2 * Math.PI;

    return {
      normalizedRadius,
      circumference
    };
  }
});

Since computed properties are supported out-of-the-box in Vue we can use it to calculate the value of stroke-dashoffset.

computed: {
  strokeDashoffset() {
    return this._circumference - percent / 100 * this._circumference;
  }
}

Next, we add our SVG as a template. Notice that the easy part here is that Vue provides us with bindings, bringing JavaScript expressions inside attributes and styles.

template: `
  <svg
    :height="radius * 2"
    :width="radius * 2"
  >
    <circle
      stroke="white"
      fill="transparent"
      :stroke-dasharray="circumference + ' ' + circumference"
      :style="{ strokeDashoffset }"
      :stroke-width="stroke"
      :r="normalizedRadius"
      :cx="radius"
      :cy="radius"
    />
  </svg>
`

When we update the progress prop of the element in our app, Vue takes care of computing the changes and update the element styles.

See the Pen Vue ProgressRing component by Jeremias Menichelli (@jeremenichelli) on CodePen.

Note: An interval was added to simulate the progress change. We do that in the next example as well.

As a React component

In a similar way to Vue.js, React helps us handle all the configuration and computed values thanks to props and JSX notation.

First, we obtain some data from props passed down.

class ProgressRing extends React.Component {
  constructor(props) {
    super(props);

    const { radius, stroke } = this.props;

    this.circumference = radius * 2 * Math.PI;
    this.normalizedRadius = radius - stroke * 2;
  }
}

Our template is the return value of the component’s render function where we use the progress prop to calculate the stroke-dashoffset value.

render() {
  const { radius, stroke, progress } = this.props;
  const strokeDashoffset = this.circumference - progress / 100 * this.circumference;

  return (
    <svg
      height={radius * 2}
      width={radius * 2}
      >
      <circle
        stroke="white"
        fill="transparent"
        strokeWidth={ stroke }
        strokeDasharray={ this.circumference + ' ' + this.circumference }
        style={ { strokeDashoffset } }
        stroke-width={ stroke }
        r={ this.normalizedRadius }
        cx={ radius }
        cy={ radius }
        />
    </svg>
  );
}

A change in the progress prop will trigger a new render cycle recalculating the strokeDashoffset variable.

See the Pen React ProgressRing component by Jeremias Menichelli (@jeremenichelli) on CodePen.

Wrap up

The recipe for this solution is based on SVG shapes and styles, CSS transitions and a little of JavaScript to compute special attributes to simulate the drawing circumference.

Once we separate this little piece, we can port it to any modern library or framework and include it in our app, in this article we explored web components, Vue, and React.

Further reading


Building a Progress Ring, Quickly is a post from CSS-Tricks

Mētis

Post pobrano z: Mētis

Kelly Sutton writes about programming, working with teams and the relationship to the Greek word Mētis:

Mētis is typically translated into English as “cunning” or “cunning intelligence.” While not wrong, this translation fails to do justice to the range of knowledge and skills represented by mētis. Broadly understood, mētis represents a wide array of practical skills and acquired intelligence in responding to a constantly changing natural and human environment.

Kelly continues:

In some ways, mētis is at direct odds with processes that need a majority of the design up-front. Instead, it prefers an evolutionary design. This system of organization and building can be maddening to an organization looking to suss out structure. The question of “When will Project X ship?” seems to be always met with weasel words and hedges.

A more effective question—although equally infuriating to the non-engineering members of the company—would be “When will our understanding of the problem increase an order of magnitude, and when will that understanding be built into the product?”

Direct Link to Article — Permalink


Mētis is a post from CSS-Tricks

Gutenberg

Post pobrano z: Gutenberg

I’ve only just been catching up with the news about Gutenberg, the name for a revamp of the WordPress editor. You can use it right now, as it’s being built as a plugin first, with the idea that eventually it goes into core. The repo has better information.

It seems to me this is the most major change to the WordPress editor in WordPress history. It also seems particularly relevant here as we were just talking about content blocks and how different CMS’s handle them. That’s exactly what Gutenberg is: a content block editor.

Rather than the content area being a glorified <textarea> (perhaps one of the most valid criticisms of WordPress), the content area becomes a wrapper for whatever different „blocks” you want to put there. Blocks are things like headings, text, lists, and images. They are also more elaborate things like galleries and embeds. Crucially, blocks are extensible and really could be anything. Like a [shortcode], I imagine.

Some images from Brian Jackson’s Diving Into the New Gutenberg WordPress Editor help drive it home:

As with any big software change, it’s controversial (even polarizing). I received an email from someone effectively warning me about it.

The consensus is this UI upgrade could either move WP into the future or alienate millions of WP site owners and kill WordPress.

I tend to think WordPress is 2-BIG-2-DIE, so probably the former.

I also think piecing together block types is a generic and smart abstraction for a CMS to make. Gutenberg seems to be handling it in a healthy way. The blocks are simply wrapped in specially formatted <!-- wp:core/text --> <!-- /wp:core/text --> to designate a block, so that the content highly compatible. A WordPress site without Gutenberg won’t have any trouble with it, nor porting it elsewhere.

Plus the content is still treated in templates as one big chunk:

To ensure we keep a key component of WordPress’ strength intact, the source of truth for the content should remain in post_content, where the bulk of the post data needs to be present in a way that is accessible and portable.

So regardless of how you structure it in the editor, it’s stored as a chunk in the database and barfed out in templates with one command. That makes it perhaps less flexible than you might want from a templating perspective, but scopes down this change to a paleteable level and remains very WordPress-y.

It seems a lot of the controversy stems from either who moved my cheese sentiments or what it does and doesn’t support at this second. I don’t put much stock in either, as people tend to find the cheese fairly quickly and this still under what seems to be heavy active development.

A big support worry is custom meta boxes. Joost de Valk:

Fact remains that, if you test Gutenberg right now, you’ll see that Yoast SEO is not on the page, anywhere. Nor, for that matter, are all the other plugins you might use like Advanced Custom Fields or CMB2. All of these plugins use so-called meta boxes, the boxes below and to the side of the current editor.

The fact that the Gutenberg team is considering changing meta boxes is, in our eyes, a big mistake. This would mean that many, many plugins would not work anymore the minute Gutenberg comes out. Lots and lots of custom built integrations would stop working. Hundreds of thousands of hours of development time would have to be, at least partly, redone. All of this while, for most sites, the current editor works just fine.

That does sound like a big deal. I wonder how easy baby stepping into Gutenberg will be. For example, enabling it for standard posts and pages while leaving it off for custom post types where you are more likely to need custom meta boxes (or some combination like that).

On this site, I make fairly heavy use of custom meta boxes (even just classic custom fields), as well as using my own HTML in the editor, so Gutenberg won’t be something I can hop on quickly. Which makes me wonder if there will always be a „classic” editor or if the new editor will be mandatory at a certain point release.

Yet more controversy came from the React licensing stuff. That went essentially like:

  1. Matt Mullenweg: we’re gonna switch away from React (which Gutenberg uses) because licencing.
  2. React: You’re all wrong but we give up. It’s MIT now.
  3. Matt Mullenweg: That’s good, but the talk now is allowing people to use whatever New JavaScript lib they want.

I’ve never heard of „framework-agnostic” block rendering, but apparently, it’s a thing. Or maybe it’s not? Omar Reiss:

With the new Gutenberg editor we’re changing the way the WordPress admin is being built. Where we now render the interface with PHP, we will start rendering more and more on the client side with JavaScript. After the editor, this is likely to become true for most of the admin. That means that if you want to integrate with the admin interface, you’ll have to integrate with the JavaScript that renders the interface. If WordPress chooses Vue, you’ll have to feed WordPress Vue components to render. If WordPress chooses React, you’ll have to feed WordPress React components to render. These things don’t go together. React doesn’t render Vue components or vice versa. There is no library that does both. If WordPress uses a particular framework, everyone will have to start using that framework in order to be able to integrate.

That’s a tricky situation right there. Before the React license change, I bet a nickel they’d go Vue. After, I suspect they’ll stick with React. Their own Calypso is all React in addition to what already exists for Gutenberg, so it seems like a continuity bonus.

This will be a fun tech story to follow! Sites like Post Status will likely be covering it closer than I’ll be able to.


Gutenberg is a post from CSS-Tricks

Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions

Post pobrano z: Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions

I work on a large team with amazing people like Simona Cotin, John Papa, Jessie Frazelle, Burke Holland, and Paige Bailey. We all speak a lot, as it’s part of a developer advocate’s job, and we’re also frequently asked where we’ll be speaking. For the most part, we each manage our own sites where we list all of this speaking, but that’s not a very good experience for people trying to explore, so I made a demo that makes it easy to see who’s speaking, at which conferences, when, with links to all of this information. Just for fun, I made use of three.js so that you can quickly visualize how many places we’re all visiting.

You can check out the live demo here, or explore the code on GitHub.

In this tutorial, I’ll run through how we set up the globe by making use of a Serverless function that gets geolocation data from Google for all of our speaking locations. I’ll also run through how we’re going to use Vuex (which is basically Vue’s version of Redux) to store all of this data and output it to the table and globe, and how we’ll use computed properties in Vue to make sorting through that table super performant and slick.

Article Series:

  1. Automatically Update GitHub Files With Serverless Functions (you are here!)
  2. Filtering and Using the Data (coming soon!)

Serverless Functions

What the heck?

Recently I tweeted that „Serverless is an actually interesting thing with the most clickbaity title.” I’m going to stand by that here and say that the first thing anyone will tell you is that serverless is a misnomer because you’re actually still using servers. This is true. So why call it serverless? The promise of serverless is to spend less time setting up and maintaining a server. You’re essentially letting the service handle maintenance and scaling for you, and you boil what you need down to functions that state: when this request comes in, run this code. For this reason, sometimes people refer to them as functions as a service, or FaaS.

Is this useful? You bet! I love not having to babysit a server when it’s unnecessary, and the payment scales automatically as well, which means you’re not paying for anything you’re not using.

Is FaaS the right thing to use all the time? Eh, not exactly. It’s really useful if you’d like to manage small executions. Serverless functions can retrieve data, they can send email notifications, they can even do things like crop images on the fly. But for anything where you have processes that might hold up resources or a ton of computation, being able to communicate with a server as you normally do might actually be more efficient.

Our demo here is a good example of something we’d want to use serverless for, though. We’re mostly just maintaining and updating a single JSON file. We’ll have all of our initial speaker data, and we need to get geolocation data from Google to create our globe. We can have it all work triggered with GitHub commits, too. Let’s dig in.

Creating the Serverless Function

We’re going to start with a big JSON file that I outputted from a spreadsheet of my coworker’s speaking engagements. That file has everything I need in order to make the table, but for the globe I’m going to use this webgl-globe from Google data arts that I’ll modify. You can see in the readme that eventually I’ll format my data to extract the years, but I’ll also need the latitude and longitude of every location we’re visiting

var data = [
    [
    'seriesA', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ],
    [
    'seriesB', [ latitude, longitude, magnitude, latitude, longitude, magnitude, ... ]
    ]
];

Eventually, I’ll also have to reduce the duplicated instances per year to make the magnitude, but we’ll tackle that modification of our data within Vue in the second part of this series.

To get started, if you haven’t already, create a free Azure trial account. Then go to the portal: ms.portal.azure.com

Inside, you’ll see a sidebar that has a lot of options. At the top it will say new. Click that.

Showing the sidebar in Azure where you can create a new service

Next, we’ll select function app from the list and fill in the new name of our function. This will give us some options. You can see that it will already pick up our resource group, subscription, and create a storage account. It will also use the location data from the resource group so, happily, it’s pretty easy to populate, as you can see in the GIF below.

Create a new function

The defaults are probably pretty good for your needs. As you can see in the GIF above, it will autofill most of the fields just from the App name. You may want to change your location based on where most of your traffic is coming from, or from a midpoint (i.e. if you have a lot of traffic both in San Francisco and New York), it might be best to choose a location in the middle of the United States.

The hosting plan can be Consumption (the default) or App Service Plan. I choose Consumption because resources are added or subtracted dynamically, which the magic of this whole serverless thing. If you’d like a higher level of control or detail, you’d probably want the App Service plan, but keep in mind that this means you’ll be manually scaling and adding resources, so it’s extra work on your part.

Modify the function once it's created

You’ll be taken to a screen that shows you a lot of information about your function. Check to see that everything is in order, and then click the functions plus sign on the sidebar.

Add in the actual function

From there you’ll be able to pick a template, we’re going to page down a bit and pick GitHub Webhook – JavaScript from the options given.

choose the github javascript template from the templates in the portal

Selecting this will bring you to a page with an `index.js` file. You’ll be able to enter code if you like, but they give us some default code to run an initial test to see everything’s working properly. Before we create our function, let’s first test it out to see that everything looks ok.

New default template

We’ll hit the save and run buttons at the top, and here’s what we get back. You can see the output gives us a comment, we get a status of 200 OK in green, and we get some logs that validate our GitHub webhook successfully triggered.

testing the default output

Pretty nice! Now here’s the fun part: let’s write our own function.

Writing our First Serverless Function

In our case, we have the location data for all of the speeches, which we need for our table, but in order to make the JSON for our globe, we will need one more bit of data: we need latitude and longitude for all of the speaking events. The JSON file will be read by our Vuex central store, and we can pass out the parts that need to be read to each component.

The file that I used for the serverless function is stored in my github repo, you can explore the whole file here, but let’s also walk through it a bit:

The first thing I’ll mention is that I’ve populated these variables with config options for the purposes of this tutorial because I don’t want to give you all my private info. I mean, it’s great, we’re friends and all, but I just met you.

// GitHub configuration is read from process.env
let GH_USER = process.env.GH_USER;
let GH_KEY = process.env.GH_KEY;
let GH_REPO = process.env.GH_REPO;
let GH_FILE = process.env.GH_FILE;

In a real world scenario, I could just drop in the data:

// GitHub configuration is read from process.env
let GH_USER = sdras;

… and so on. In order to use these environment variables (in case you’d also like to store them and keep them private), you can use them like I did above, and go to your function in the dashboard. There you will see an area called Configured Features. Click application settings and you’ll be taken to a page with a table where you can enter this information.

Working with our dataset

First, we’ll retrieve the original JSON file from GitHub and decode/parse it. We’re going to use a method that gets the file from a GitHub response and base64 encodes it (more information on that here).

module.exports = function(context, data) {
 // Make the context available globally
 gContext = context;

 getGithubJson(githubFilename(), (data, err) => {
   if (!err) {
     // No error; base64 decode and JSON parse the data from the Github response
     let content = JSON.parse(
       new Buffer(data.content, 'base64').toString('ascii')
     );

Then we’ll retrieve the geo-information for each item in the original data, if it went well, we’ll push it back up to GitHub, otherwise, it will error. We’ll have two errors: one for a general error, and another for if we get a correct response but there is a geo error, so we can tell them apart. You’ll note that we’re using gContext.log to output to our portal console.

getGeo(makeIterator(content), (updatedContent, err) => {
       if (!err) {
         // we need to base64 encode the JSON to embed it into the PUT (dear god, why)
         let updatedContentB64 = new Buffer(
           JSON.stringify(updatedContent, null, 2)
         ).toString('base64');
         let pushData = {
           path: GH_FILE,
           message: 'Looked up locations, beep boop.',
           content: updatedContentB64,
           sha: data.sha
         };
         putGithubJson(githubFilename(), pushData, err => {
           context.log('All done!');
           context.done();
         });
       } else {
         gContext.log('All done with get Geo error: ' + err);
         context.done();
       }
     });
   } else {
     gContext.log('All done with error: ' + err);
     context.done();
   }
 });
};

Great! Now, given an array of entries (wrapped in an iterator), we’ll walk over each of them and populate the latitude and longitude, using Google Maps API. Note that we also cache locations to try and save some API calls.

function getGeo(itr, cb) {
 let curr = itr.next();
 if (curr.done) {
   // All done processing- pass the (now-populated) entries to the next callback
   cb(curr.data);
   return;
 }

 let location = curr.value.Location;

Now let’s check the cache to see if we’ve already looked up this location:

 if (location in GEO_CACHE) {
   gContext.log(
     'Cached ' +
       location +
       ' -> ' +
       GEO_CACHE[location].lat +
       ' ' +
       GEO_CACHE[location].long
   );
   curr.value.Latitude = GEO_CACHE[location].lat;
   curr.value.Longitude = GEO_CACHE[location].long;
   getGeo(itr, cb);
   return;
 }

Then if there’s nothing found in cache, we’ll do a lookup and cache the result, or let ourselves know that we didn’t find anything:

 getGoogleJson(location, (data, err) => {
   if (err) {
     gContext.log('Error on ' + location + ' :' + err);
   } else {
     if (data.results.length > 0) {
       let info = {
         lat: data.results[0].geometry.location.lat,
         long: data.results[0].geometry.location.lng
       };
       GEO_CACHE[location] = info;
       curr.value.Latitude = info.lat;
       curr.value.Longitude = info.long;
       gContext.log(location + ' -> ' + info.lat + ' ' + info.long);
     } else {
       gContext.log(
         "Didn't find anything for " + location + ' ::' + JSON.stringify(data)
       );
     }
   }
   setTimeout(() => getGeo(itr, cb), 1000);
 });
}

We’ve made use of some helper functions along the way that help get Google JSON, and get and put GitHub JSON.

Now if we run this function in the portal, we’ll see our output:

Running the function and seeing the console: status 200 ok

It works! Our serverless function updates our JSON file with all of the new data. I really like that I can work with backend services without stepping outside of JavaScript, which is familiar to me. We need only git pull and we can use this file as the state in our Vuex central store. This will allow us to populate the table, which we’ll tackle the next part of our series, and we’ll also use that to update our globe. If you’d like to play around with a serverless function and see it in action for yourself, you can create one with a free trial account.

Stay tuned for the next installment!

Article Series:

  1. Automatically Update GitHub Files With Serverless Functions (you are here!)
  2. Filtering and Using the Data (coming soon!)

Exploring Data with Serverless and Vue: Automatically Update GitHub Files With Serverless Functions is a post from CSS-Tricks

A Five Minutes Guide to Better Typography

Post pobrano z: A Five Minutes Guide to Better Typography

Pierrick Calvez with, just maybe, a bunch of typographic advice that you’ve heard before. But this is presented very lovingly and humorously.

Repeating the basics with typography feels important in the same way repeating the basics of performance does. Gzip your stuff. Make your line length readable. Set far expires headers. Make sure you have hierarchy. Optimize your images. Align left.

Let’s repeat this stuff until people actually do it.

Direct Link to Article — Permalink


A Five Minutes Guide to Better Typography is a post from CSS-Tricks

Help Your Users `Save-Data`

Post pobrano z: Help Your Users `Save-Data`

The breadth and depth of knowledge to absorb in the web performance space is ridiculous. At a minimum, I’m discovering something new nearly every week. Case in point: The Save-Data header, which I discovered via a Google Developers article by Ilya Grigorik.

If you’re looking for the tl;dr version of how Save-Data works, let me oblige you: If you opt into data savings on the Android version of Chrome (or the Data Saver extension on your desktop device), every request that Chrome sends to a server will contain a Save-Data header with a value of On. You can then act on this header to change your site’s content delivery in such a way that conserves data for the user. This is a very open-ended sort of opportunity that you’re being given, so let’s explore a few ways that you could act on the Save-Data header to send less bytes down the wire!

Change your image delivery strategy

I don’t know if you’ve noticed, but images are often the largest chunk of the total payload of any given page. So perhaps the most impactful step you can take with Save-Data is to change how images are delivered. What I settled on for my blog was to rewrite requests for high DPI images to low DPI images. When I serve image sets like this on my site, I do so using the <picture> element to serve WebP images with a JPEG or PNG fallback like so:

<picture>
  <source srcset="/img/george-and-susan-1x.webp 1x, /img/george-and-susan-2x.webp 2x">
  <source srcset="/img/george-and-susan-1x.jpg 1x, /img/george-and-susan-2x.jpg 2x">
  <img src="/img/george-and-susan-1x.jpg" alt="LET'S NOT GET CRAZY HERE" width="320" height="240">
</picture>

This solution is backed by tech that’s baked into modern browsers. The <picture> element delivers the optimal image format according to a browser’s capabilities, while srcset will help the browser decide what looks best for any given device’s screen. Unfortunately, both <picture> and srcset lacks control over which image source to serve for users who want to save data. Nor should they! That’s not the job of srcset or <picture>.

This is where Save-Data comes in handy. When users visit my site and send a Save-Data request header, I use mod_rewrite in Apache to serve low DPI images in lieu of high DPI ones:

RewriteCond %{HTTP:Save-Data} =on [NC]
RewriteRule ^(.*)-2x.(png|jpe?g|webp)$ $1-1x.$2 [R=302,L]

If you’re unfamiliar with mod_rewrite, the first line is a condition that checks if the Save-Data header is present and contains a value of on. The [NC] flag merely tells mod_rewrite to perform a case-insensitive match. If the condition is met, the RewriteRule looks for any requests for a PNG, JPEG or WebP asset ending in -2x (the high DPI version), and redirects such requests to an asset ending in -1x (the low DPI version). The R=302 flag signals to the browser that this is a temporary (302) redirect. Since the user can toggle Data Saver on or off at will, we don’t want to send a permanent (301) redirect, as the browser will cache it. Caching the redirect ensures that it will be in effect even if Data Saver is turned off later on.

Image delivery with Save-Data turned on

Aren’t redirects bad for performance? Most of the time, yes. Redirects add to latency because it takes longer for a request to be resolved. In this instance, however, it’s a fitting solution. We don’t want to rewrite requests without redirecting them because then low-quality images get cached under the same URLs as high-quality ones. What if the user connects to a wifi network, turns off Data Saver, and return to the site at a later time? The low-quality image will be served from the cache, even when Data Saver is turned off. That’s not at all what we want. If the user isn’t using Data Saver, we should assume the default image delivery strategy.

Of course, there are other ways you could change your image delivery in the presence of Save-Data. For example, Cory Dowdy wrote a post detailing how he uses Save-Data to serve lower quality images. Save-Data gives you lots of room to devise an image delivery strategy that makes the best sense for your site or application.

Opt out of server pushes

Server push is good stuff if you’re on HTTP/2 and can use it. It allows you send assets to the client before they ever know they need them. The problem with it, though, is it can be weirdly unpredictable in select scenarios. On my site, I use it to push CSS only, and this generally works well. Although, I do tailor my push strategy in Apache to avoid browsers that have issues with it (i.e., Safari) like so:

<If "%{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">
  Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style; nopush"
</If>
<Else>
  Header add Link "</css/global.5aa545cb.css>; rel=preload; as=style"
</Else>

In this instance, I’m saying „Hey, I want you to preemptively push my site’s CSS to people, but only if they’re not using Safari.” Even if Safari users come by, they’ll still get a preload resource hint (albeit with a nopush attribute to discourage my server from pushing anything).

Even so, it would behoove us to be extra cautious when it comes to pushing assets for users with Data Saver turned on. In the case of my blog, I decided I wouldn’t push anything to anyone who had Data Saver enabled. To accomplish this, I made the following change to the initial <If> header:

<If "%{HTTP:Save-Data} == 'on' || %{HTTP_USER_AGENT} =~ /^(?=.*safari)(?!.*chrome).*/i">

This is the same as my initial configuration, but with an additional condition that says „Hey, if Save-Data is present and set to a value of on, don’t be pushing that stylesheet. Just preload it instead.” It might not be a big change, but it’s one of those little things that could help visitors to avoid wasted data if a push was in vain for any reason.

Change how you deliver markup

With Save-Data, you could elect to change what parts of the document you deliver. This presents all sorts of opportunities, but before you can embark on this errand, you’ll need to check for the Save-Data header in a back end language. In PHP, such a check might look something like this:

$saveData = (isset($_SERVER["HTTP_SAVE_DATA"]) && stristr($_SERVER["HTTP_SAVE_DATA"], "on") !== false) ? true : false;

On my blog, I use this $saveData boolean in various places to remove markup for images that aren’t crucial to the content of a given page. For example, one of my articles has some animated GIFs and other humorous images that are funny little flourishes for users who don’t mind them. But they are heavy, and not really necessary to communicate the central point of the article. I also remove the header illustration and a teeny tiny thumbnail of my book from the nav.

Image markup delivery with Data Saver on and off

From a payload perspective, this can certainly have a profound effect:

The potential effects of Data Saver on page payload

Another opportunity would be to use the aforementioned $saveData boolean to put a save-data class on the <html> element:

<html class="<?php if($saveData === true) : echo("save-data"); endif; ?>">

With this class, I could then write styles that could change what assets are used in background-image properties, or any CSS property that references external assets. For example:

/* Just a regular ol' background image */
body {
  background-image: url("/images/bg.png");
}

/* A lower quality background image for users with Data Saver turned on */
.save-data body {
  background-image: url("/images/bg-lowsrc.png");
}

Markup isn’t the only thing you could modify the delivery of. You could do the same for videos, or even do something as simple as delivering fewer search results per page. It’s entirely up to you!

Conclusion

The Save-Data header gives you a great opportunity to lend a hand to users who are asking you to help them, well, save data. You could use URL rewriting to change media delivery, change how you deliver markup, or really just about anything that you could think of.

How will you help your users Save-Data? Leave a comment and let your ideas be heard!


Cover of Web Performance in Action

Jeremy Wagner is the author of Web Performance in Action, available now from Manning Publications. Use promo code sswagner to save 42%.

Check him out on Twitter: @malchata


Help Your Users `Save-Data` is a post from CSS-Tricks

Boilerform

Post pobrano z: Boilerform

This is just a random idea, but I can’t stop it from swirling around in my head.

Whenever I need to style a form on a fresh project where the CSS and style guide stuff is just settling in, the temptation to reach for a mini form framework is strong. Form elements are finicky, have little cross-browser issues, and are sometimes downright hard to wrassle styling control from.

This idea, which I’m just now managing to write about, but haven’t actually done any work toward, would be this mini form framework. Maybe something like „Boilerform”, as Dave jokingly suggested on an episode of ShopTalk.

I imagine it something like this:

  1. It would have basic form styling to organize form elements, not unlike something like Foundation forms.
  2. It would account for cross browser issues, not unlike normalize.css.
  3. It would include strongarming styling control over form elements, not unlike WTF, forms?
  4. It would include native browser form validation stuff, including UX improvements via native JavaScript API’s, not unlike Validate.js.

I think there is value in combining those things into one thing, but doing so…

  1. With a light touch, being as unopinionated about the final styling as possible
  2. With flexibility, perhaps showing off a gallery of different form types with different styling.

I probably don’t have time to head up a project like this, but I wouldn’t mind helping connect humans who also see value here and wanna give it a shot.


Boilerform is a post from CSS-Tricks