Archiwum kategorii: CSS

Productivity Tip: Time Tracking and Task Lists, Unite!

Post pobrano z: Productivity Tip: Time Tracking and Task Lists, Unite!

I’ve shared this little productivity tip with enough folks who have found it useful and figured I’d make a post out of it.

I love time tracking and I love task lists, but boy do I hate managing them both. So, I’ve been using my time tracker as my task list.

I use Harvest for time tracking. It allows you to create time entries in the future and I suspect many other time tracking apps do the same. That means today I can enter all the time entries I plan on doing tomorrow. Or, if I’m feeling super organized, I can create entries for the following week. All of my tasks are right there in front of me and ready to clock my time.

If I don’t get to a task that day? No worries. Harvest has a subtle feature that allows me to move a time entry from one day to another. Now, I’m good to go for the nest day.

Again, other apps are probably capable of doing the same.

I know, it’s a super small thing but it delights me every day and helps me manage two important things in one.

The post Productivity Tip: Time Tracking and Task Lists, Unite! appeared first on CSS-Tricks.

CSS Techniques and Effects for Knockout Text

Post pobrano z: CSS Techniques and Effects for Knockout Text

Knockout text is a technique where words are clipped out of an element and reveal the background. In other words, you only see the background because the letters are knocking out holes. It’s appealing because it opens up typographic styles that we don’t get out of traditional CSS properties, like color.

While we’ve seen a number of ways to accomplish knockout text in the past, there are some modern CSS properties we can use now and even enhance the effect further, like transitions and animations. Let’s see them in action.

Mix Blend Modes

There are four blend modes that effortlessly make text cutouts: multiply, screen, darken, and lighten. Applying these to the top element of a stack of image and text, text being at top, creates the knockout design.

Even though, in most cases, either black or white is used in these blend modes to get a clear distinction between the text and the background, I prefer using a darker or lighter color instead to keep the back image slightly visible, like this:

<div class="backdrop">
  <p class="text">Taitō</p>
</div>
/* Background layer with an image */
.backdrop {
  background: url("/path/to/image.jpg") center;
  ...
}
    
/* Dark foreground layer, with white text, set to "multiply" mix blend mode */
.text {
  color: white;
  background: rgb(59, 2, 6);
  mix-blend-mode: multiply;
  ...
}

See the Pen CSS Knockout Text by Preethi (@rpsthecoder) on CodePen.

Using a darker (or lighter) color also creates a nice „theme” going on with the image shown through the text.

The multiply blend mode keeps darker colors dark and the lighter colors let through whatever’s behind them: a black portion on the top layer will be fully opaque and white will be fully transparent.

The effects of the multiply mix blend mode.

In the above example, the white text became completely see-through while the darker color around it lets the image behind be seen only a little, as the darker shades remain unaffected.

The screen blend mode reverses the roles: darker colors create translucence while lighter shades remain light and block what’s behind.

The darken and lighten blend modes are similar to multiply and screen, respectively, except that details are lost on the portions of the back image that can be seen. Rather than mixing the shades, the modes choose the darker or the lighter shade of the two layers that are shown.

See below the difference in how the four modes have blended the colors:

/* Knockout text within a dark area */
.multiply {
  color: white;
  mix-blend-mode: multiply;
  background-color: rgb(59, 2, 6);
}

/* Knockout text within a bright area */
.screen {
  color: black;
  mix-blend-mode: screen;
  background-color: rgb(244, 220, 211);
}

/* Knockout text within a dark area that's less detailed */
.darken {
  color: white;
  mix-blend-mode: darken;
  background-color: rgb(59, 2, 6);
}

/* Knockout text within a light area that's less detailed */
.lighten {
  color: black;
  mix-blend-mode: lighten;
  background-color: rgb(244, 220, 211);
}

See the Pen CSS Knockout Text by Preethi (@rpsthecoder) on CodePen.

Using a blend mode is the most convenient option to get a knockout text effect, because it allows us to apply additional styles that other techniques might not allow.

Let’s take a closer look at the styles we can use to enhance the knockout effect.

Shadow Blur

Adding a white/black or a light/dark text shadow to the text creates a blurred effect. For example, let’s say I add a text-shadow that’s with a large blur radius value:

.text {
  text-shadow: 0 0 9px white;
  ...
}

Now the edges are less crisp and give a sort of cloudy effect:

See the Pen CSS Blurred Knockout Text by Preethi (@rpsthecoder) on CodePen.

Animation

We can even make things move around a little. For example, let’s take build on the text-shadow idea we looked at above and put some movement on it to make it appear that the text is glowing:

.text {
  animation:  glow 3s infinite;
  ...
}

@keyframes glow {
  0% {
    text-shadow:  0 0 10px white;
  }
  
  15% {
    text-shadow: 2px 2px 10px rgba(255, 255, 255, 1),
                 -2px -2px 10px rgba(255, 255, 255, 1);
  }
  30% {
    text-shadow: 2px 2px 4px rgba(255, 255, 255, .7),
                 -2px -2px 4px rgba(255, 255, 255, .7);
  }
  50% {
    text-shadow: 20px 20px 50px rgba(255, 255, 255, .5),
                 -20px -20px 50px rgba(255, 255, 255, .5);
  }
}

See the Pen CSS knockout Text Glow Animation by Preethi (@rpsthecoder) on CodePen.

Transition

Transition is another property we can apply to our knockout text and that opens up even more interesting possibilities, like using text-indent on pseudo-classes like :hover.

Here’s how we can use transition on pseudo-classes to introduce a new element into the knockout text:

/* The knockout text */
.text {
  transition: text-indent .5s;
  ...
}

/* On hover, trigger the transition */
.text:hover {
  text-indent: 5px;
  transition: text-indent .5s;
}

/* The thing that slides in on hover */
.text:hover::before {
  display: inline-block;
  content: '✈︎';
}

See the Pen CSS Knockout Text Transition by Preethi (@rpsthecoder) on CodePen.

Background Clip

The background-clip CSS property set with the text value clips a background to the shape of its foreground text.

Using background-clip: text
<p class="text">Taitō</p>
.text {
  background: url("/path/to/image.jpg") center;
  background-clip: text;
  color: transparent;
  ...
}

See the Pen Knockout Text by Preethi (@rpsthecoder) on CodePen.

The transparent text shows the image behind it that’s already cut to the shape of the text. Although this is a true knockout text approach—it literally removes the text’s surrounding background on screen—having no background left to bleed into or move over leaves little space for other effects like blur, or moving text, to take place. That’s where mix-blend-mode has an advantage.

CSS Mask

The first technique we looked at employs masking, a concept where shapes are created on a foreground layer and use color to determine how much of the shape shows the background. The black parts of the foreground hide (or „mask”) and white parts reveal the background, or vice-versa. Any gray value between black and white is treated as varying degrees of partial transparency.

CSS mask works the same way: you straight up declare an image to be the mask applied over another image and, depending on the type of the mask, we get a portion cut out. As of writing this post CSS mask is fully supported in Firefox only.

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

Desktop

Chrome Opera Firefox IE Edge Safari
67* 52* 53 No No TP*

Mobile / Tablet

iOS Safari Opera Mobile Opera Mini Android Android Chrome Android Firefox
11.3* 37* No 62* 64* 57

Since we are looking specifically into knockout text, the mask needs to be made from text. This is a great use for SVG <mask>, which can create masks from SVG shapes and texts.

<div class="backdrop">
  <p class="text"></p>
</div>

<svg>
  <defs>
    <mask id="m">
      <rect width="100%" height="100%" fill="white" />
      <text x="50%" y="75%" text-anchor="middle">Taitō</text>
    </mask>
  </defs>
</svg>
/* Background layer with an image */
.backdrop {
  background:  url("/path/to/image.jpg") center;
  ...
}

/* Dark foreground layer with masking applied */
.text {
  background-color: rgba(59, 2, 6, 1);
  mask-type: luminance;
  /* Referrer to an SVG mask */
  mask: url("#m");              
  ...
}

svg {
  width: 75vw;
  height: 20vw;
}

/* SVG text inside the mask */
text {
  font: bolder 12vw 'Alfa Slab One';
}

See the Pen Knockout Text by Preethi (@rpsthecoder) on CodePen.

The luminance value on the mask-type property of the foreground element implements a masking mechanism where parts of this layer, corresponding to the black parts of the mask, become transparent. The parts corresponding to the white portions of the mask remain opaque. The mask property uses the url() value to designate the SVG element used for the mask.

SVG’s <mask> element creates a mask imaged from its contents. The contents I made inside the <mask> are a white rectangle (<rect>) and black text (<text>). The text, being black, brings up the portion of the image behind it to the view after masking.

Blurring, Animation, and Transition

CSS masks open up the same blur and animation effects we were able to use with mix-blend-mode.

That same glowing text from we used before applies here as well, this time applied directly to the <text> element of the SVG:

text {
  font: bolder 12vw 'Alfa Slab One';
  animation: glow 3s infinite;
}

@keyframes glow {
  0% {
    text-shadow: 0 0 10px white;
  }
  
  15% {
    text-shadow: 2px 2px 10px rgba(255, 255, 255, 1),
                 -2px -2px 10px rgba(255, 255, 255, 1);
  }
  30% {
    text-shadow: 2px 2px 4px rgba(255, 255, 255, .7),
                 -2px -2px 4px rgba(255, 255, 255, .7);
  }
  50% {
    text-shadow: 20px 20px 50px rgba(255, 255, 255, .5),
                 -20px -20px 50px rgba(255, 255, 255, .5);
  }
}

However, unlike mix-blend-mode, not all the same properties can be animated. For example, text-indent won’t work here and neither will transform. It’s true that CSS transforms can be applied to SVG elements but because our mask is actually being used as a mask in its truest form, browsers might not apply those transformations.

We can always inject a transform SVG attribute using JavaScript, delivering those transformations to the elements inside the mask:

t = document.querySelector('text');
b = document.querySelector('.backdrop');
b.onmouseover = ()=>{
  t.setAttribute('transform', 'translate(20)');
}
b.onmouseout = ()=>{
  t.removeAttribute('transform');
}

Conclusion

When it comes to browser support and production safe code, CSS mask lags behind due to being limited to Firefox support. The blend modes mentioned in this post are supported in almost all the major browsers, except Edge. The background-clip property is also supported by all the browsers, but still requires -webkit prefix.

In terms of result, both blend modes and mask give similar output. Between background-clip and mix-blend-mode values, it’ll be the choice of the design that’ll lead to choosing one over another. What you can achieve with background-clip can also be done by blending, provided you’re using either only black or white background matching the page’s body.

TLDR; knockout text method uno: apply one of the four knockout-friendly blend modes to the top layer of a text-image stack and use dark/light (or black/white) color combination on the text and its enclosure. Method dos: set background-clip to text in the element carrying both a background image and a transparent text. Method tres: use CSS masking on a solid foreground with an image behind and dictate the cutout using an SVG text mask.

The post CSS Techniques and Effects for Knockout Text appeared first on CSS-Tricks.

AMP News

Post pobrano z: AMP News

AMP is controversial, to say the least. Dave and I did a show on it about a year ago that to me felt fairly balanced in addressing some of the issues. Let’s cover some recent news and responses.

One thing that isn’t usually controversial: it’s fast. AMP pages are damn performant. Even that, though, is contentious. Ferdy Christant notes:

Technically correct AMP pages will perform very similar to any non-horrible web page.

The difference between AMP performing instantly and getting numbers ranging from 2–8s as seen above have to be explained.

Part of that answer you can probably guess: the cache is simply very fast. It’s hard to compete with a Google-class CDN.

You don’t need AMP to have a fast website.

FYI @CityLab article pages load faster than @nytimes AMP pages. Just to show you do not need AMP to have fast loading pages #webperf pic.twitter.com/34YboEBwLP

— Michael Donohoe (@donohoe) February 23, 2018


The most controversial bit is that carrot offered for using AMP: the search results news carousel. The carousel is extremely prominent in Google search results, and AMP is a one-way ticket to get in. You could make a site faster than AMP, but that doesn’t meet the criteria for entry. Tim Kadlec:

there has been no indication of any attempt to address the first issue, that of incentivization and premium placement. In fact, not only has there been no attempt to fix it, it appears the AMP team is doubling-down on those incentives instead.

Doubling-down, as in, AMP stories will be released soon and will also enjoy premium placement on Google. Every indication is that the primary desire of people reaching for AMP is the preferential search results treatment. Gina Trapani:

In my experience people are motivated to use AMP… I’ve seen this from our clients…mostly because of SEO. They want it in that top stories carousel, they want that lightning bolt of approval in regular search results which is happening now.

Of course, Google can do whatever they want. They are an independent company and if they wanna tell us that we have to use a special format to have benefits on their platform, then that’s the way it is. It doesn’t mean we have to be happy about it. Hundreds of people have signed the AMP letter, which calls for two changes:

  1. Instead of granting premium placement in search results only to AMP, provide the same perks to all pages that meet an objective, neutral performance criterion such as Speed Index. Publishers can then use any technical solution of their choice.
  2. Do not display third-party content within a Google page unless it is clear to the user that they are looking at a Google product. It is perfectly acceptable for Google to launch a “news reader” but it is not acceptable to display a page that carries only third-party branding on what is actually a Google URL, nor to require that third party to use Google’s hosting in order to appear in search results.

Ethan Marcotte is concerned:

absent action from some sort of regulatory body, I’m not sure what influence you or I could exert to change the trajectory of AMP

…but thinks we could perhaps collectively have influence. Jeremy Keith has called some of the messaging behind AMP an outright lie:

I don’t think the developers working on the AMP format are intentionally deceptive (although they are engaging in some impressive cognitive gymnastics). The AMP ecosystem, on the other hand, that’s another story—the preferential treatment of Google-hosted AMP pages in the carousel and in search results; that’s messed up.

Jeremy also notes that the power Google is exerting here is worrisome. Part of the stated motivation is trying to fix the web. Taking a stand, as it were.

I remember feeling very heartened to see WikiPedia, Google and others take a stand on January 18th, 2012 (against SOPA and PIPA). But I also remember feeling uneasy. In this particular case, companies were lobbying for a cause I agreed with. But what if they were lobbying for a cause I didn’t agree with? Large corporations using their power to influence politics seems like a very bad idea. Isn’t it still a bad idea, even if I happen to agree with the cause?

Cloudflare quite rightly kicked The Daily Stormer off their roster of customers. Then the CEO of Cloudflare quite rightly wrote this in a company-wide memo:

Literally, I woke up in a bad mood and decided someone shouldn’t be allowed on the Internet. No one should have that power.

There’s an uncomfortable tension here.

AMP is also expanding to other technology, notably email. Well, Gmail, that is. Fast, well-rendering, interactive emails seem like a hugely positive thing. Perhaps predictably at this point, people in that industry have similar concerns. Jason Rodriguez:

I’m an email guy. I’ve written three books on email, spoken at a bunch of conferences on the topic, and help build tools for other email folks at my day job. I love seeing the email platform grow and evolve. I love seeing people working on interesting ideas that make email more valuable for the subscribers that receive them.

So, you’d think I’d be thrilled by Google’s announcement about adding dynamic content and interactivity to Gmail with AMP for Email. You’d be wrong.

Jason’s primary concern being that instead of improving support for what we already have, they’ve invented a new format and called it open-sourced, but have full control over it. However, with far more blockers in the way (e.g. ESPs not supporting the new MIME type) and less carrots to offer, it seems like a long shot it will happen.

I know I’ve covered a lot of negative news here, but that’s mostly what I’ve been seeing. Strangely enough, I feel more interested in watching how this all shakes out than I am motivated to weigh in on either side.


AMP News is a post from CSS-Tricks

Working Towards Better Naming

Post pobrano z: Working Towards Better Naming

There is a quote that I bet every one of you has heard many times. You know the one. The one that reminds you how hard naming is.

Let’s talk names.

We talk often about how hard naming is, but it’s less common see people talk about how to get better at it. Even naming philosophies lend structure to naming, but don’t pick names for you. Names are more than just some hard thing we get needlessly caught up in. They’re essential to good code. Good names can make a code base easy to pick up and work with. Bad names are hard to understand, or worse yet, prone to error.

Naming Examples

Let’s look at some examples in JavaScript.

function processData(data) {
  var result = JSON.parse(data);
  return result;
}

Reading only the function name, parameter name, and returned variable, we see that processData gets data and returns a result. These names have added nearly zero information to the reader. Code like this is easy to write when you just want to get it working or you’re trying to stay flexible to changes, and that’s okay. It’s always a good idea to go over your code with fresh eyes to fix things, and names should be on your quality checklist.

Here’s a more descriptive way we could have written the last example:

function parseJson(string) {
  var jsonObject = JSON.parse(string);
  return jsonObject;
}

Technology is one of the most abbreviation and acronym heavy fields there are, and they are key to great names. FTP is easier to read and understand than „File Transfer Protocol.” In some cases though, the reader can be left out.

Here’s an example where the abbreviations are convenient for the developer writing the code, but not so handy for anyone else who needs to read or contribute to it:

function cts(con, ack) {
  if (con && ack) {
    return true;
  }
  else {
    return false;
  }
}

Often I’ll read code with an acronym and have to switch to my web browser to do a search, only to find results for car models. A perfect example of that is cts, which returns a lot of Cadillac results. ack does show up on a search, but I’d rather not leave it my text editor. con can be misunderstood many ways. Is it a connection? A count? A container? Maybe it’s a scam. These things may be obvious if you are familiar with the code base, but it adds a learning curve to those joining the project. A few extra seconds can save several minutes for readers over years.

Here’s the previous example written without abbreviations:

function clearToSend(connectionExists, acknowledgementStatus) {
  if (connectionExists && acknowledgementStatus) {
    return true;
  }
  else {
    return false;
  }
}

Let’s turn to some HTML examples because HTML is perhaps the most name heavy language of them all.

<section class="new-promotion-parent">
  <img class="logo" src="small-square-logo-monochrome.png"/>
  <div class="get-your-coupon">
    <p>Get Your Coupon</p>
  </div>
</section>

We can imagine that the word „new” was used here likely because a designer was told to update the promotion-parent element, but to also keep support for the existing class, maybe for old HTML floating about. The term „new” is an accurate description for the first few months, but over time it becomes more and more ironic. A better idea might be to add a separate class that describes what is new. For example, if a new flat design is being implemented, then a class name of flat-design might work. For an added bonus, you can let the CSS from the existing promotion-parent class cascade if you’d like to reuse some of the styles.

Similarly, logo seems like a sensible class name at first. Inevitably, however, a second logo will come along somewhere, which gets the name alt-logo. The logos keep coming, and so do the increasingly bad names. Most assets have several variations, such as different shapes, sizes, color schemes and more. That said, small-square-logo-monochrome wouldn’t be a great class name either, because the image itself should be able to be swapped without the class name becoming obsolete. A better idea might be a name that describes the role of the asset rather than the type or appearance.

Here, the language of the div has been used to name the div get-your-coupon. The content of an HTML document is meant to continually evolve; names are not. A coupon code today might be an email signup in the future, while keeping the same styles and functionality. HTML is one place where names are often too specific instead of too vague.

Here’s that same HTML code taking the suggestions into consideration:

<section class="flat-design promotion-parent">
  <img class="promotion-branding-image" src="small-square-logo-monochrome.png"/>
  <div class="primary-promotion-text">
    <p>Get Your Coupon</p>
  </div>
</section>

We can even look at the names in a database for better naming. Tables often get used countless times across an application in several very different contexts.

Here’s a simplified database table:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `type` bit(1) NOT NULL,
  `sort` int(12) NOT NULL,
  `order` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

What does type mean in the context of books? Does it mean fiction or non-fiction? Does it mean paperback or hardcover? Maybe it means physical or digital?

The sort column is equally confusing. Is it representing ASC or DESC? Does it represent which column is being used to sort? Maybe it decides if sorting is active? Or maybe it decides show the books in some other alternate order?

And then there’s order. Aside from being equally ambiguous, order is a reserved word in MySQL and many other languages. You can work around this using backticks (`) for MySQL, but it’s probably a better idea to avoid using reserved words altogether.

Here’s how the table could be written in a more descriptive way:

CREATE TABLE `book` (
  `id` int(12) NOT NULL,
  `title` varchar(50) NOT NULL,
  `author` varchar(50) NOT NULL,
  `cover_type` bit(1) NOT NULL,
  `sort_order` int(12) NOT NULL,
  `purchase_order_number` varchar(25) NOT NULL,
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Naming Conventions

Let’s talk naming conventions.

if (oldmanshaven) {
  return true;
}

Did you read that as Old Mans Haven or Old Man Shaven? Either way, it forces you to slow down and think which adds up and might one day lead to a misunderstanding. PascalCase, camelCase, snake_case, kebab-case are all excellent choices. Use them, and just as important, be consistent.

Here’s that same code in snake_case, which is less likely to be misread:

if (old_man_shaven) {
  return true;
}

One more example:

if (!isNaN(number)) {
  alert('not a number')
}
else if (!number > 50) {
  alert('number too large')
}
else if (!number < 10) {
  alert('number too small')
}
else {
  // code here
}

I looked at some of my first lines of code for inspiration writing this post. I didn’t see many bad names because I wrote code in a way that didn’t use names. I used very few functions, rarely used assignments, and would abuse variables by making them do a dozen different things. Having plenty of names in your code is often a sign that you’re abstracting things properly.

Here’s one example from my code:

function validateNumber(number) {
  var maximumValue = 50;
  var minimumValue = 10;
  if (isNaN(number)) {
    alert('not a number')
    return false;
  }
  if (number > maximumValue) {
    alert('number too large')
    return false;
  }
  if (number < minimumValue) {
    alert('number too small')
    return false;
  }
}

if (validateNumber(number)) {
  // code here
}

Caveats

Naming things is an art, not a science. There’s some things outside the name to consider when evaluating if a name is good or bad.

Context

Context can give generic terms much more meaning. For example, „item” is a vague name but, in the context of a getCustomerSalesOrder() function, we can tell it likely refers to a product that was purchased. A function that is short, focused, and takes context into account can reduce the need for verbose names. I still prefer a good name. Context can disappear easily over time as functions get longer or re-factored. Names are more permanent markers of meaning.

Comments

Code comments are important to readable code, but they can’t do it all by themselves. Comments should pick up where names leave off, giving details you can’t cram into a name, noting the reason for a particular way of doing things, or ranting about a broken library.

/* This refers to a product that was purchased and relates to the customer-sales-order class. */
.product-item {
  display: block;
  text-transform: uppercase;
  width: 100vw;
}

Reading Length

Longer names create more to read and wider lines. It can especially be problematic when accessing deep into an array, such as:

$order_details['customer']['ship_to_address']['default']['street_address']['line_1']

That said, even that straw man example I just gave, while verbose, is crystal clear and gives me no reason to stop reading to think or look over the rest of the function to understand the context.

Names are everywhere in Code

Most of the characters of a code file probably aren’t brackets or syntax, but names. It might be variable names, function names, HTML tags or attributes, database tables or columns, or any of the countless things that we give names to in any given project.

I still struggle with naming things. I often find myself sitting frozen at my text editor, trying to name some minor variable. I’ve learned that when that happens, it’s likely because I’m dealing with something difficult to conceptualize, which makes it all the more important to find the right name for it.


Working Towards Better Naming is a post from CSS-Tricks

Everything you need to know about CSS Variables

Post pobrano z: Everything you need to know about CSS Variables

This is by far the biggest deep dive I’ve seen on CSS Variables posted to the web and it’s merely Chapter One of complete e-book on the topic.

Truth is, I’m still on the thick of reading through this myself, but had to stop somewhere in the middle to write this up and share it because it’s just that gosh-darned useful. For example, the post goes into great detail on three specific use cases for CSS Variables and breaks the code down to give a better understanding of what it does, in true tutorial fashion.

Scoping, inheritance, resolving multiple declarations, little gotchas—there’s plenty in here for beginners and advanced developers alike.

OK, back to reading. 🤓

Direct Link to ArticlePermalink


Everything you need to know about CSS Variables is a post from CSS-Tricks

Let’s Build a Custom Vue Router

Post pobrano z: Let’s Build a Custom Vue Router

Plenty of tutorials exist that do a great job in explaining how Vue’s official routing library, vue-router, can be integrated into an existing Vue application. vue-router does a fantastic job by providing us with the items needed to map an application’s components to different browser URL routes.

But, simple applications often don’t need a fully fledged routing library like vue-router. In this article, we’ll build a simple custom client-side router with Vue. By doing so, we’ll gather an understanding of what needs to be handled to construct client-side routing as well as where potential shortcomings can exist.

Though this article assumes basic knowledge in Vue.js; we’ll be explaining things thoroughly as we start to write code!

Routing

First and foremost: let’s define routing for those who may be new to the concept.

In web development, routing often refers to splitting an application’s UI based on rules derived from the browser URL. Imagine clicking a link and having the URL go from https://website.com to https://website.com/article/. That’s routing.

Routing is often categorized in two main buckets:

  • Server-side routing: the client (i.e. the browser) makes a request to the server on every URL change.
  • Client-side routing: the client only makes a request to the server upon initial-page load. Any changes to the application UI based on URL routes are then handled on the client.

Client-side routing is where the term single-page application (or SPA for short) comes in. SPAs are web apps that load only once and are dynamically updated with user interaction without the need to make subsequent requests to the server. With routing in SPAs, JavaScript is the driving force that dynamically renders different UI.

Now that we have a brief understanding of client-side routing and SPAs, let’s get an overview of what we’ll be working on!

Case Study: Pokémon

The app we aim to construct is a simple Pokémon app that displays details of a particular Pokémon based on the URL route.

The application will have three unique URL routes: /charizard, /blastoise, and /venusaur. Based on the URL route entered, a different Pokémon will be shown:

In addition, footer links exist at the bottom of the application to direct the user to each respective route upon click:

Do We Even Need Routing for This?

For simple applications like this, we don’t necessarily need a client-side router to make our app functional. This particular app could be composed of a simple parent-child component hierarchy that uses Vue props to dictate the information that should be displayed. Here’s a Pen that shows just this:

See the Pen Vue Pokemon by Hassan Dj (@itslit) on CodePen.

Though the app would functionally work, it misses a substantial feature that’s expected from most web applications—responding to browser navigation events. We’d want our Pokémon app to be accessible and to show different details for different pathnames: /charizard, /blastoise, and /venusaur. This would allow users to refresh different pages and keep their location in the app, bookmark the URLs to come back to later, and potentially share the URL with others. These are some of the main benefits of creating routes within an application.

Now that we have an idea of what we’ll be working on, let’s start building!

Preparing the App

The easiest way to follow along step-by-step (if you wish to do so) is to clone the GitHub repo I’ve set up.

Download on GitHub

When cloned, install the project dependencies with:

npm install

Let’s take a brief look within the project directory.

$ ls
README.md
index.html
node_modules/
package.json
public/
src/
static/
webpack.config.js

There also exists the hidden files, .babelrc and .gitignore within the project scaffold.

This project is a simple webpack-configured application scaffolded with vue-cli, the Vue command line interface.

index.html is where we declare the DOM element—#app— with which we’ll use to mount our Vue application:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.5.3/css/bulma.css">
    <link rel="stylesheet"
      href="../public/styles.css" />
    <title>Pokémon - Routing</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/dist/build.js"></script>
  </body>
</html>

In the <head> tag of the index.html file, we introduce Bulma as our application’s CSS framework and our own styles.css file that lives in the public/ folder.

Since our focus is on the usage of Vue.js, the application already has all the custom CSS laid out.

The src/ folder is where we’ll be working directly from:

$ ls src/
app/
main.js

src/main.js represents the starting point of our Vue application. It’s where our Vue instance is instantiated, where we declare the parent component that is to be rendered, and the DOM element #app with which our app is to be mounted to:

import Vue from 'vue';
import App from './app/app';

new Vue({
  el: '#app',
  render: h => h(App)
});

We’re specifying the App component, from the src/app/app.js file, to be the main parent component of our application.

In the src/app directory, there exists two other files – app-custom.js and app-vue-router.js:

$ ls src/app/
app-custom.js
app-vue-router.js
app.js

app-custom.js denotes the completed implementation of the application with a custom Vue router (i.e. what we’ll be building in this article). app-vue-router.js is a completed routing implementation using the vue-router library.

For the entire article, we’ll only be introducing code to the src/app/app.js file. With that said, let’s take a look at the starting code within src/app/app.js:

const CharizardCard = {
  name: 'charizard-card',
  template: `
    <div class="card card--charizard has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/charizard.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Charizard</div>
          <div class="hp">hp 78</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">🔥<br>
            <span class="tag is-warning">Type</span>
          </div>
          <div class="column center-column">199 lbs<br>
            <span class="tag is-warning">Weight</span>
          </div>
          <div class="column">1.7 m <br>
            <span class="tag is-warning">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <pokemon-card></pokemon-card>
      </div>
    </div>
  `,
  components: {
    'pokemon-card': CharizardCard
  }
};

export default App;

Currently, two components exist: CharizardCard and App. The CharizardCard component is a simple template that displays details of the Charizard Pokémon. The App component declares the CharizardCard component in its components property and renders it as <pokemon-card></pokemon-card> within its template.

We currently only have static content with which we’ll be able to see if we run our application:

npm run dev

And launch localhost:8080:

To get things started, let’s introduce two new components: BlastoiseCard and VenusaurCard that contains details of the Blastoise and Venusaur Pokémon respectively. We can lay out these components right after CharizardCard:

const CharizardCard = { 
  // ... 
};

const BlastoiseCard = {
  name: 'blastoise-card',
  template: `
    <div class="card card--blastoise has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/blastoise.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Blastoise</div>
          <div class="hp">hp 79</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">💧<br>
            <span class="tag is-light">Type</span>
          </div>
          <div class="column center-column">223 lbs<br>
            <span class="tag is-light">Weight</span>
          </div>
          <div class="column">1.6 m<br>
            <span class="tag is-light">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const VenusaurCard = {
  name: 'venusaur-card',
  template: `
    <div class="card card--venusaur has-text-weight-bold has-text-white">
      <div class="card-image">
        <div class="card-image-container">
          <img src="../../static/venusaur.png"/>
        </div>
      </div>
      <div class="card-content has-text-centered">
        <div class="main">
          <div class="title has-text-white">Venusaur</div>
          <div class="hp hp-venusaur">hp 80</div>
        </div>
        <div class="stats columns is-mobile">
          <div class="column">🍃<br>
            <span class="tag is-danger">Type</span>
          </div>
          <div class="column center-column">220 lbs<br>
            <span class="tag is-danger">Weight</span>
          </div>
          <div class="column">2.0 m<br>
            <span class="tag is-danger">Height</span>
          </div>
        </div>
      </div>
    </div>
  `
};

const App = { 
  // ... 
};

export default App;

With our application components established, we can now begin to think how we’ll create routing between these components.

router-view

To establish routing, we’ll start by buiding a new component that holds the responsibility to render a specified component based on the app’s location. We’ll create this component in a constant variable named View.

Before we create this component, let’s see how we might use it. In the template of the App component, we’ll remove the declaration of <pokemon-card> and instead render the upcoming router-view component. In the components property; we’ll register the View component constant as <router-view> to be declared in the template.

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
      </div>
    </div> 
  `,
  components: {
    'router-view': View
  }
};

export default App;

The router-view component will match the correct Pokémon component based on the URL route. This matching will be dictated in a routes array that we’ll create. We’ll create this array right above the App component:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  {path: '/', component: CharizardCard},
  {path: '/charizard', component: CharizardCard},
  {path: '/blastoise', component: BlastoiseCard},
  {path: '/venusaur', component: VenusaurCard}
];

const App = { 
  // ... 
};

export default App;

We’ve set each Pokémon path to their own respective component (e.g. /blastoise will render the BlastoiseCard component). We’ve also set the root path / to the CharizardCard component.

Let’s now begin to create our router-view component.

The router-view component will essentially be a mounting point to dynamically switch between components. One way we can do this in Vue is by using the reserved <component> element to establish Dynamic Components.

Let’s create a starting point for router-view to get an understanding of how this works. As mentioned earlier; we’ll create router-view within a constant variable named View. So with that said, let’s set up View right after our routes declaration:

const CharizardCard = { 
  // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [
  // ...
];

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: CharizardCard  
    }
  }
}; 

const App = {
// ... 
};

export default App;

The reserved <component> element will render whatever component the is attribute is bound to. Above, we’ve attached the is attribute to a currentView data property that simply maps to the CharizardCard component. As of now, our application resembles the starting point by displaying CharizardCard regardless of what the URL route is.

Though router-view is now appropriately rendered within App, it’s not currently dynamic. We need router-view to display the correct component based on the URL pathname upon page load. To do this, we’ll use the created() hook to filter the routes array and return the component that has a path that matches the URL path. This would make View look something like this:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {
    this.currentView = routes.find(
      route => route.path === window.location.pathname
    ).component;
  }
};

In the data function, we’re now instantiating currentView with an empty object. In the created() hook, we’re using JavaScript’s native find() method to return the first object from routes that matches route.path === window.location.pathname. We can then get the component with object.component (where object is the returned object from find()).

Inside a browser environment, window.location is a special object containing the properties of the browser’s current location. We grab the pathname from this object which is the path of the URL.

At this stage; we’ll be able to see the different Pokémon Card components based on the state of our browser URL!

The BlastoiseCard component now renders at the /blastoise route.

There’s something else we should consider. If a random URL pathname is entered, our app will currently error and present nothing to the view.

To avoid this, let’s introduce a simple check to display a „Not Found” template if the URL pathnamedoesn’t match any path existing in the routes array. We’ll separate out the find() method to a component method named getRouteObject() to avoid repetition. This updates the View object to:

const View = {
  name: 'router-view',  
  template: `<component :is="currentView"></component>`,  
  data() {  
    return {  
      currentView: {}  
    }
  },
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    } 
  },
  methods: {
    getRouteObject() {
      return routes.find(
        route => route.path === window.location.pathname
      );
    }
  }
};

If the getRouteObject() method returns undefined, we display a „Not Found” template. If getRouteObject()returns an object from routes, we bind currentView to the component of that object. Now if a random URL is entered, the user will be notified:

The „Not Found” view is rendered if the URL pathname does not match any of the values in the routes array.

The „Not Found” template tells the user to pick a Pokémon from a list. This list will be the links we’ll create to allow the user to navigate to different URL routes.

Awesome! Our app is now responding to some external state, the location of the browser. router-view determines which component should be displayed based on the app’s location. Now, we need to construct links that will change the location of the browser without making a web request. With the location updated, we want to re-render our Vue app and rely on router-view to appropriately determine which component to render.

We’ll label these links as router-link components.

router-link

In web interfaces, we use HTML <a> tags to create links. What we want here is a special type of <a> tag. When the user clicks on this tag, we’ll want the browser to skip its default routine of making a web request to fetch the next page. Instead, we just want to manually update the browser’s location.

Let’s compose a router-link component that produces an <a> tag with a special click binding. When the user clicks on the router-link component, we’ll use the browser’s history API to update the browser’s location.

Just like we did with router-view, let’s see how we’ll use this component before we build it.

In the template of the App component, let’s create three <router-link> elements within a parent <div class="pokemon-links"></div> element. Rather than using the href attribute in <router-link>, we’ll specify the desired location of the link using a to attribute. We’ll also register the upcoming router-link component (from a Link constant variable) in the App components property:

const App = {
  name: 'App',
  template: `
    <div class="container">
      <div class="pokemon">
        <router-view></router-view>
  
        <div class="pokemon-links has-text-centered">
          <router-link to="/charizard"></router-link>
          <router-link to="/blastoise"></router-link>
          <router-link to="/venusaur"></router-link>
        </div>
      </div>
    </div>
  `,
  components: {
    'router-view': View,
    'router-link': Link
  }
};

We’ll create the Link object that represents router-link right above the App component. We’ve established the router-link component should always be given a to attribute (i.e. prop) that has a value of the target location. We can enforce this prop validation requirement like so:

const CharizardCard = { 
 // ... 
};
const BlastoiseCard = { 
  // ... 
};
const VenusaurCard = { 
  // ... 
};

const routes = [ 
  // ... 
];

const View = { 
  // ... 
};

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  }
};

const App = { 
  // ... 
};

export default App;

We can create the template of router-link to consist of an <a> tag with an @click handler attribute. Upon trigger, the @click handler will call a component method, labeled navigate(), that navigates the browser to the desired location. This navigation will occur with the use of the history.pushState() method. With that said, the Link constant object will be updated to:

const Link = {
  name: 'router-link',
  props: {
    to: {
      type: String,
      required: true
    }
  },
  template: `<a @click="navigate" :href="to">{{ to }}</a>`,
  methods: {  
    navigate(evt) {  
      evt.preventDefault();  
      window.history.pushState(null, null, this.to);  
    }
  }
};

Within the <a> tag, we’ve bound the value of the to prop to the element text content with {{ to }}.

When navigate() is triggered, it first calls preventDefault() on the event object to prevent the browser from making a web request for the new location. The history.pushState() method is then called to direct the user to the desired route location. history.pushState() takes three arguments:

  • a state object to pass serialized state information
  • a title
  • the target URL

In our case, there is no state information that’s needed to be passed, so we’ve left the first argument as null. Some browsers (e.g. Firefox) currently ignore the second parameter, title, hence we’ve left that as null as well.

The target location, the to prop, is passed in to the third and last parameter. Since the to prop contains the target location in a relative state, it will be resolved relative to the current URL. In our case, /blastoise will resolve to http://localhost:8080/blastoise.

If we click any of the links now, we’ll notice our browser updates to the correct location without a full page reload. However, our app will not update and render the correct component.

This unexpected behaviour happens because when router-link is updating the location of the browser, our Vue app is not alerted of the change. We’ll need to trigger our app (or simply just the router-view component) to re-render whenever the location changes.

Though there’s a few ways to accomplish this behaviour, we’ll do this by using a custom EventBus. An EventBus is a Vue instance responsible in allowing isolated components to subscribe and publish custom events between each other.

At the beginning of the file, we’ll import the vue library and create an EventBus with a new Vue() instance:

import Vue from 'vue';

const EventBus = new Vue();

When a link has been clicked, we need to notify the necessary part of the application (i.e. router-view) that the user is navigating to a particular route. The first step is to create an event emitter using the EventBus’s events interface in the navigate() method of router-link. We’ll give this custom event a name of navigate:

const Link = {
  // ...,
  methods: {
    navigate(evt) {
      evt.preventDefault();
      window.history.pushState(null, null, this.to);
      EventBus.$emit('navigate'); 
    }
  }
};

We can now set the event listener/trigger in the created() hook of router-view. By setting the custom event listener outside of the if/else statement, the created() hook of View will be updated to:

const View = {
  // ...,
  created() {  
    if (this.getRouteObject() === undefined) {
      this.currentView = {
        template: `
          <h3 class="subtitle has-text-white">
            Not Found :(. Pick a Pokémon from the list below!
          </h3>
        `
      };
    } else {
      this.currentView = this.getRouteObject().component;
    }

    // Event listener for link navigation
    EventBus.$on('navigate', () => {
      this.currentView = this.getRouteObject().component;
    });
  },
  // ...
};

When the browser’s location changes by clicking a <router-link> element, this listening function will be invoked, re-rendering router-view to match against the latest URL!

Great! Our app now navigates appropriately as we click each of the links.

There’s one last thing we need to consider. If we try to use the browser back/forward buttons to navigate through the browser history, our application will not currently re-render correctly. Although unexpected, this occurs because no event notifier is emitted when the user clicks browser back or browser forward.

To make this work, we’ll use the onpopstate event handler.

The onpopstate event is fired each time the active history entry changes. A history change is invoked by clicking the browser back or browser forward buttons, or calling history.back() or history.forward() programmatically.

Right after our EventBus creation, let’s set up the onpopstate event listener to emit the navigate event when a history change is invoked:

window.addEventListener('popstate', () => {  
  EventBus.$emit('navigate');  
});

Our application will now respond appropriately even when the browser navigation buttons are used!

And there we have it! We’ve just built a custom Vue router using an EventBus and dynamic components. Even with the tiny size of our app we can enjoy a noticeable performance improvement. Avoiding a full page load also saves hundreds of milliseconds and prevents our app from „blinking” during the page change.

Conclusion

I love Vue. One reason as to why – it’s incredibly easy to use and manipulate Vue components just like we saw in this article.

In the introduction, we mentioned how Vue provides the vue-router library as the official routing library of the framework. We’ve just created simple versions of the same main items that are used in vue-router:

  • routes: the array responsible in mapping components to respective URL pathnames.
  • router-view: the component that renders a specified app component based on the app’s location
  • router-link: the component that allows the user to change the location of the browser without making a web request.

For very simple applications, the routing we’ve built (or a variation thereof like this one built by Chris Fritz) can do the minimal amount of work needed to route our applications.

The vue-router library, on the other hand, is built in a more complicated manner and introduces incredibly useful capabilities, often needed in larger applications like:

Though the vue-router library does come with additional boilerplate, it’s fairly easy to integrate once your application is composed of well isolated and distinct components. If you’re interested, you can see the components of vue-router being used to enable routing in this application here.

Hopefully this was as enjoyable to you as it was for me in compiling this post! Thanks for reading!


This article is an adapted (and summarized) segment from the upcoming book, Fullstack Vue, that I’m working on with the Fullstack.io team! Having the opportunity to work with the folks at Fullstack has been nothing short of being a blast. In true Fullstack fashion, the book covers numerous facets of Vue including but not restricted to routing, simple state management, form handling, Vuex, server persistence, and testing. If this is something that piques your interest or if you have any questions at all, follow (or message) me on twitter (@djirdehh)! If the above doesn’t pique your interest, you can still follow me anyway. 😛


Let’s Build a Custom Vue Router is a post from CSS-Tricks

The Red Reveal: Illusions on the Web

Post pobrano z: The Red Reveal: Illusions on the Web

In part one of a series of posts about optical illusions on the web, Dan Wilson looks at how to create the “Red Reveal” that he happens to describe like this:

Growing up, my family played a lot of board games. Several games such as Outburst, Password, and Clue Jr. included something that amazed me at the time — a red lens and cards with some light blue text that was obscured by a myriad of red lines. When you put the red lens over the card, the text would magically appear.

Here’s one example of that effect from a nifty Pen:

I’d also recommend reading part two in this series, Barrier Grid Animation, which uses a bunch of CSS techniques to trick your eye into seeing an animation of several static images.

Direct Link to ArticlePermalink


The Red Reveal: Illusions on the Web is a post from CSS-Tricks

My Talk Writing Process

Post pobrano z: My Talk Writing Process

Some people have a talk preparation process that is super organized and runs like a well-oiled machine. Mine, on the other hand, is a bit messy, but it works for me. Even when a talk looks polished and put together on stage, it doesn’t mean the process to get it there was that way too.

Me on stage at An Event Apart.

When putting together a new talk recently, I noticed there was most definitely a pattern to how my talks take shape. Here’s how the talk-making process goes for me:

The Research Phase

True to the nature of research, all my talks start by collecting articles, books, videos, and other things that relate to the topic of the talk. At this point in the talk development process, I usually only have a general topic idea instead of a fully fleshed out point-of-view or main message. That means I end up collecting things that might only be tangentially related to the topic and going down some strange topical rabbit holes.

I’ll save all these as a collection of bookmarks but usually also in a Google Doc with notes or quotes from the piece that seem most relevant. That makes it easier to keep a high-level view of what I’ve collected, and even discover interesting threads that connect some of the seemingly unrelated sources.

This initial phase is intentionally fuzzy on focus. Only a small percentage of the research I collect actually makes it to the end talk content. Sometimes the things that don’t make it spark ideas for other talks, or just gets filed away in my brain for future (hopefully interesting) things.

Outlining: The Giant Mess Phase

There’s probably a smarter sounding name for this phase, but for every talk I’ve done, there’s always a point where I step back and think, „Holy crap this is all a giant mess! What am I even doing with all this!?” So, that’s what I’ll call this phase. This is the phase where I make a general outline for the talk (again in a Google Doc or Word file) and start fitting my thoughts, examples or demos, and relevant research into it.

I outline the major points I think the talk should make and try to fit them into some sort of narrative order. These tend to change and morph a bit as the talk takes shape, but that’s OK because I’m still in the giant mess phase.

At the top of my document I have a three-part block that helps keep me focused:

What is the main question this talk answers (or the main problem it addresses)?

What is the main message of this talk?

Three points that support the main message:

(I started doing this on advice from Bill Smartt, and it’s been a huge help ever since.)

A talk outline for a 30 min talk complete with comments to myself.

The rest of the document addresses the body of the talk with each main point as a headline and some notes underneath it. Personally, I don’t write out talks word-for-word and memorize them. I do write out an introduction and conclusion to make sure I’m setting up the topic and summarizing it well, but the rest of the notes are bulleted lists of points to make and references supporting examples, demos, or references. I leave space at the bottom of the document for random thoughts and notes as well as probably a few too many comments to myself on possible changes to make or different directions to take. Points that don’t fit into the main narrative get moved down to this section too.

Once I feel like I have a cohesive outline, or at least one that isn’t a total mess, I move on to making some visuals.

The Editing Phase

A recent talk with all the edited-out slides shown ghosted out. Those slides never made it to the final talk.

This is the point where I start making slides and such based on the outline. Some people leave slides to the very last thing, but I leave them more to the almost last thing and do some of my thinking and organizing while I build up the slide deck.

I’ll make slides for each point in the outline, take screen recordings of demos or examples, and start piecing things together in order. I tend to think of my talks in sections at this point and, as I create the slides for each section, I’ll try talking through them out loud to see how they flow. (It’s amazing how different things sound when you say them out loud!)

There is a lot of rearranging and cutting out during this phase to work towards something that feels cohesive. I keep working on adding, deleting, and rearranging slides until I’ve got visuals for the full narrative of my outline. Sometimes things fall into place quickly, but for most talks this part can take a while.

At this point I almost always have far too much content. I’ll run through what I have for the talk in 10 to 15 minute chunks, editing down and solidifying points until I’ve got something that fits neatly into the required time length. Most times this means a 30 minutes and 45-60 minute version of the talk depending on the format of the event where it’s being given.

The same talk without the slides that have been edited out.

Rehearsing: The Talking to Myself Phase

Rehearsing is so important but it can also be very awkward. It seems like everyone has a different strategy for rehearsing talks, which totally makes sense. I have a really hard time rehearsing talks in their entirety when I’m standing in my office talking to the wall or to the dog, so I tend to rehearse in 15 or 30 minute chunks; practicing the first half then taking a break to do some other things and coming back to run through the second half. That way I know I have a handle on all the material, but haven’t driven myself (or the dog) up a wall with all that talking to no one in particular.

Ah, that familiar presenter notes view. I like a giant notes window even though I rarely actually read them while I’m on stage. They’re a „just in case” kind of thing.

As often as possible I’ll try to give a new talk to a few friends or at a meetup before doing it on stage for the first time. Having a real live human audience can really help show which points are strong and which might need a bit more work to get across well. I also always run through the „final” talk from start-to-finish at least once in the 24 hours before I’ll be on stage to make sure all the content is fresh in my mind.

A Talk is Never Really Done

Seriously. They really never are. The funny thing about talks is that when you give them more than once, they’re rarely exactly the same. (Yes, it is totally fine to do the same talk more than once.) There is always something to improve, something to add, or new points or examples to add to the narrative.

I usually make notes for myself on what worked or what didn’t right after getting off stage. That’s a good time to recall which parts of the talk felt like they could use some work, but it’s not such a good time to actually make any edits. I’ll go back to those notes a few days later (having some space here is really helpful) and make adjustments as needed. Also, if I come across other relevant examples or research at any point in time, I’ll try to add them into the talk for the next time around.

You Do You

If there’s one thing I’ve learned working on talks and talking to other speakers about their process, it’s that no two people work the same way. Everyone has their own way of putting together talks that they’ve customized for their own habits and preferences. If your talk development process looks nothing like mine, that’s totally fine. And if you haven’t found a process that works for you yet, keep experimenting with different techniques. You’ll find one that works for you!

For more on how to get a talk together, check out these other articles too:


My Talk Writing Process is a post from CSS-Tricks

Shipping system fonts to GitHub.com

Post pobrano z: Shipping system fonts to GitHub.com

System font stacks got hot about a year ago, no doubt influenced by Mark Otto’s work putting them live on GitHub.

The why, to me, feels like (1) yay performance and (2) the site looks like the rest of the operating system. But to Mark:

Helvetica was created in 1957 when the personal computer was a pipe dream. Arial was created in 1982 and is available on 95% of computers across the web. Millions, if not billions, of web pages currently use this severely dated font stack to serve much younger content to much younger browsers and devices.

As display quality improves, so too must our use of those displays. System fonts like Apple’s San Francisco and Microsoft’s Segoe aim to do just that, taking advantage of retina screens, dynamic kerning, additional font-weights, and improved readability. If operating systems can take advantage of these changes, so too can our CSS.

I also like the team’s idea of adding emoji fonts at the end of the font declaration so that you have the best support possible for those too:

p { 
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

Direct Link to ArticlePermalink


Shipping system fonts to GitHub.com is a post from CSS-Tricks

Gotchas When Publishing Modules in npm and Bower

Post pobrano z: Gotchas When Publishing Modules in npm and Bower

Bower and npm are de-facto the package managers of the web. I doubt there are many front-end developers out there who haven’t heard of them or used them to manage dependencies.

Whilst many of us use them as consumers, one day you might decide to share a project of your own and become a contributor! This happened to me recently. I had the experience of publishing my open-source library on npm and Bower.

Although their official docs were quite good, I still ended up struggling with three little known gotchas. I won’t focus on the basics in this post. You can always find and read about them. I’ll instead focus on the gotchas.

Nowadays, it looks like even Bower tells people not to use Bower. However, in 2018, there are still many projects that depend on it. The state of JavaScript in 2017 survey shows that around 24% of surveyed developers still use Bower as a package manager. Therefore, I think it might take a little while before we see the end of Bower, which means it’s probably still worth supporting it to cover legacy-package-managed projects. I feel the pain of those of you working on a legacy project—that’s why I chose to publish my open source module there, too.

My hope is that after this you’ll be one step ahead when you decide to share your code with the world. Without any further ado, here are some gotchas I’ve come across when managing packages.

Removing a Package From npm

Why bother spending hours choosing a name, when you can focus on shipping the features first? In my first experience with npm, I was unfortunate to leave the name of my project „test-something.”

Guess what? A few days later, I found out that the un-publish option in the npm public registry is only allowed with versions published in the last 24 hours. If you are trying to un-publish a version published more than a day ago then you must contact support.

They state that it is generally considered bad practice to delete a library that other people depend on. I understand that but I’m 100% sure that no projects depend on a package called „test something.”

I was about to leave things alone, but my test package was going to be visible forever in my shiny npm user profile. Dislike!

I contacted support and they handled my request within the very same day. They still didn’t want to completely un-publish it but they did transfer it to the @npm user account and deprecated it with a deprecation note. This removed it from my profile (woohoo!) and from the search results. However, if someone knows the exact URL (or name) they can still install it. While that’s not totally ideal, the deprecation note will still be an alert that the package is no longer supported.

I think this might be related to the 11 lines of code, that Azer Koçulu deleted from npm and which kind of broke the internet for a moment. Safety first.

The moral of the story: make sure to choose your package name wisely!

Exporting Modules

Another gotcha I encountered was how to export my module. I wanted to do it in a universal way so that anyone can import it to the browser in any of the three most popular approaches. For example…

…with ES6:

// If a transpiler is configured (like webpack, Babel, Traceur Compiler or Rollup):
import MyModule from 'my-module';

…with CommonJS:

// If a module loader is configured (like RequireJS, Browserify or Neuter):
const MyModule = require('my-module');

…or by referencing the script file in the HTML:

<script ="/node_modules/my-module/index.js"></script>

What I was actually looking for is the Universal Module Definition pattern. It’s a pattern that provides a clean way to expose your module to different environments that consume modules in a variety of ways.

This pattern has a couple of variations, depending on what you really need. However, modules written this way are capable of working everywhere, be it in the client, on the server or elsewhere.

The standard pattern is:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['dependency'], factory);
	} else if (typeof module === 'object' && module.exports) {
		  // Node. Does not work with strict CommonJS, but
		  // only CommonJS-like environments that support module.exports,
		  // like Node.
		  module.exports = factory(require('dependency'));
	} else {
    // Browser globals (root is window)
    root.returnExports = factory(root.dependency);
	}
}(this, function (dependency) {
  // Use dependency in some fashion.
  return {
    // Your module goes here
  };
}));

If you’re using Grunt, Gulp or webpack, you’ll find that there is a plugin that can wrap your modules like this for you. Plus, it’s in the core of webpack already!

Managing Distribution Files

This one was really tricky.

I am building a package for npm and Bower. I followed the pattern to keep the working files (ES6) in the src/ package directory and build my distribution files (ES5, compiled with Babel) in the dist/ directory.

I ignore the entire dist/ folder in the .gitignore file. You know the drill: source control should only contain source. If it’s generated from the source, it doesn’t belong there—it should be generated by your build process instead.

On the one hand (npm), I have a .npmignore which does exactly the opposite and ignores src/ instead of dist/. On npm, I only want my distribution files. That works out perfectly well.

On the other hand (Bower), the dist/ folder is missing in the repository and, therefore, the Bower package doesn’t include it. You see, Bower tracks your publicly available Git endpoint only. By pushing Git tags you release a new version on the Bower registry. Yes, it can ignore files, but they are related only to the files in your repository.

So, how can I publish the ignored by git dist/ folder contents on Bower?

I’m not sure it’s possible to do. The only workaround I found is to commit the distribution files in the repository. If you really want to keep those distribution files out of the repo, the trick is to commit them right before you release a tag. Release a tag. Remove them.

There is one more use case that gives me some peace of mind. Imagine somebody downloads a ZIP of your repository and drops it into their project. They won’t need your fancy build step. The production source is already there. All right, maybe that’s not so bad after all.

Wrapping Up

Both npm and Bower continue to be widely used and helpful ways to manage project dependencies, even if Bower is bowing out. While they’re great at what they do, being the owner and a contributor to a package listed in either package directory presents some challenges for us and I hope the ones I’ve outlined here help save other some time and possible headache.

Do you know any other ways to handle the gotchas covered here? Or have stumbled into gotchas of your own? Let me know in the comments!


Gotchas When Publishing Modules in npm and Bower is a post from CSS-Tricks