Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

February 19 2020

07:30
8 Super Useful WordPress Plugins for Your Website
03:39
How to Create a Credit Card Icon
Sponsored post
soup-sponsored
05:36
Reposted bySchrammelhammelMrCoffeinmybetterworldkonikonikonikonikoniambassadorofdumbgroeschtlNaitliszpikkumyygittimmoe

February 18 2020

22:33

Centering a div That Maintains Aspect-Ratio When There’s Body Margin

Andrew Welch had a little CSS challenge the other day to make an ordinary div:

• centered vertically + horizontally
• scales to fit the viewport w/ a margin around it
• maintains an arbitrary aspect ratio
• No JS

There's a video in that tweet if it helps you visualize the challenge. I saw Paul Bakaus blogging about this the other day, too, so it's a thing that comes up!

Mark Huot got fancy applying aspect ratios directly with width/height and creating the margins from subtracting from those dimensions:

CodePen Embed Fallback

Amelia Wattenberger's idea is to set both height/width and max-height/max-width with viewport units, and center it with the classic translate trick:

CodePen Embed Fallback

Eric A. Meyer did the same, only centered with flexbox instead.

Brian Hart used vmin units for the aspect ratio sizing and centered it with flexbox:

CodePen Embed Fallback

Benoît Rouleau did the same but used calc() for the margins in a different unit.

Andrew really likes Jonathan Melville's approach. Most of it is in Tailwind classes so it's a smidge hard for me to understand as I'm not used to looking at code like that yet.

CodePen Embed Fallback

Andrew said he ultimately went with the vmin thing — although I see he's using calc() to subtract vmin units from each other which isn't really necessary unless, I guess, you wanna see the math.

The post Centering a div That Maintains Aspect-Ratio When There’s Body Margin appeared first on CSS-Tricks.

21:56

An Out of the Box Rebranding

Just before the 2020 new year, we decided it was a good time to refresh the Boxes and Arrows brand identity, a time to start a fresh decade with a fresh logo. And, after a few weeks at the drawing board, we’re liking the results. 

 ⬇

To us, the new, dynamic, and pleasingly symmetrical icon—a box made of arrows—represents the emerging dimensions of information spaces, greater interconnected continuity between people, and an ever-expanding collection of knowledge which we hope to bring to our readers. 

During most of our careers in IA and UX, Boxes and Arrows has been there along the way, and we want to make this history of still relevant articles more navigable and easily shareable for connecting with others who have a more in-depth need in our daily professions. In this, the three arrows represent the portability, the shareability, and the potential in our content. We want B&A to be an accessible and social source for improving the world of design, and we think our new identity reflects how we intend to provide a history and a future for information and design professionals.

We wanted to bring the brand into the future, both symbolizing the depth of content in our 18-year history and expanding it to be more accessible and relevant. Boxes and Arrows has attracted, supported and reinforced the knowledge of information architects and experience designers (among many other titles) for many years and we plan to keep going. 

Returning to our roots, we now aim to even bring more experienced and professional approaches to the world of information spaces. Boxes and Arrows will continue to be written by new voices, industry experts and leaders, and will remain a free resource to anyone who wants to plan, organize, design, and build better experiences.

With this mission in mind, we feel that our new brand identity brings in some needed freshness, reflects on the large inventory of Boxes and Arrows content, and keeps us solidly in the line of thinking we always have been. 

Thank you, dear readers, for your neverending support. We hope you enjoy the new brand as much as we do. 

The post An Out of the Box Rebranding appeared first on Boxes and Arrows.

20:38

Solving Sticky Hover States with @media (hover: hover)

Mezo Istvan does a good job of covering the problem and a solution to it in a blog post on Medium¹.

If you tap on something that has a :hover state but you don't leave the page then, on a mobile device, there is a chance that :hover state "sticks." You'll see this with stuff like jump-links used as tabs or buttons that trigger on-page functionality.

button:hover {
  border: 3px solid green; /* might stick! */
}

The solution, or trick, is a new(ish) "CSS4" media query that allows you only to apply styles on devices with hover capability.

@media (hover: hover) {
  button:hover {
    border: 3px solid green; /* solves sticky problem */
  }
}

Your typical touch screen mobile device will fail that media query, the style won't apply, and you'll avoid the sticky problem.

Support is solid, so not much worry there.

  1. It almost feels like we have to apologize to linking to things on Medium lately. I have no idea what you're going to experience when you get there. Will you just be able to read it? Will it be a teaser where you have to log in to read more? Will it be behind a paywall? I have no idea. In this case, hopefully, this link post has enough info in it that isn't not blocking you from learning anything.


Direct Link to ArticlePermalink

The post Solving Sticky Hover States with @media (hover: hover) appeared first on CSS-Tricks.

15:27

How to Build Vue Components in a WordPress Theme

Intrigued by the title and just wanna see some code? Skip ahead.

A few months ago, I was building a WordPress website that required a form with a bunch of fancy conditional fields. Different options and info were required for different choices you could make on the form, and our client needed complete control over all fields 1. In addition, the form needed to appear in multiple places in each page, with slightly different configs.

And the header instance of the form needed to be mutually exclusive with the hamburger menu, so that opening one closes the other.

And the form had text content that was relevant to SEO.

And we wanted the server response to present some cute animated feedback.

(Phew.)

The whole thing felt complex enough that I didn't want to handle all that state manually. I remembered reading Sarah Drasner’s article "Replacing jQuery With Vue.js: No Build Step Necessary” which shows how to replace classic jQuery patterns with simple Vue micro-apps. That seemed like a good place to start, but I quickly realized that things would get messy on the PHP side of WordPress.

What I really needed were reusable components

PHP → JavaScript

I love the static-first approach of Jamstack tools, like Nuxt, and was looking to do something similar here — send the full content from the server, and progressively enhance on the client side.

But PHP doesn’t have a built-in way to work with components. It does, however, support require-ing files inside other files 2. WordPress has an abstraction of require called get_template_part, that runs relative to the theme folder and is easier to work with. Dividing code into template parts is about the closest thing to components that WordPress provides 3.

Vue, on the other hand, is all about components — but it can only do its thing after the page has loaded and JavaScript is running.

The secret to this marriage of paradigms turns out to be the lesser-known Vue directive inline-template. Its great and wonderful powers allow us to define a Vue component using the markup we already have. It’s the perfect middle ground between getting static HTML from the server, and mounting dynamic DOM elements in the client.

First, the browser gets the HTML, then Vue makes it do stuff. Since the markup is built by WordPress, rather than by Vue in the browser, components can easily use any information that site administrators can edit. And, as opposed to .vue files (which are great for building more app-y things), we can keep the same separation of concerns we use for the whole site — structure and content in PHP, style in CSS, and functionality in JavaScript.

To show how this all fits together, we’re going to build a few features for a recipe blog. First, we’ll add a way for users to rate recipes. Then we’ll build a feedback form based on that rating. Finally, we’ll allow users to filter recipes, based on tags and rating.

We’ll build a few components that share state and live on the same page. To get them to play nicely together — and to make it easy to add additional components in the future — we’ll make the whole page our Vue app, and register components inside it.

Each component will live in its own PHP file and be included in the theme using get_template_part.

Laying the groundwork

There are a few special considerations to take into account when applying Vue to existing pages. The first is that Vue doesn't want you loading scripts inside it — it will send ominous errors to the console if you do. The easiest way to avoid this is to add a wrapper element around the content for every page, then load scripts outside of it (which is already a common pattern for all kinds of reasons). Something like this:

<?php /* header.php */ ?>

<body <?php body_class(); ?>>
<div id="site-wrapper">
<?php /* footer.php */ ?> 

</div> <!-- #site-wrapper -->
<?php wp_footer(); ?>

The second consideration is that Vue has to be called at the end of body element so that it will load after the rest of the DOM is available to parse. We’ll pass true as the fifth argument  (in_footer) for the wp_enqueue_script  function. Also, to make sure Vue is loaded first, we’ll register it as a dependency of the main script.

<?php // functions.php

add_action( 'wp_enqueue_scripts', function() {
  wp_enqueue_script('vue', get_template_directory_uri() . '/assets/js/lib/vue.js', null, null, true); // change to vue.min.js for production
  wp_enqueue_script('main', get_template_directory_uri() . '/assets/js/main.js', 'vue', null, true);

Finally, in the main script, we’ll initialize Vue on the site-wrapper element.

// main.js

new Vue({
  el: document.getElementById('site-wrapper')
})

The star rating component

Our single post template currently looks like this:

<?php /* single-post.php */ ?>

<article class="recipe">
  <?php /* ... post content */ ?>

  <!-- star rating component goes here -->
</article>

We’ll register the star rating component and add some logic to manage it:

// main.js

Vue.component('star-rating', {
  data () {
    return {
      rating: 0
    }
  },
  methods: {
    rate (i) { this.rating = i }
  },
  watch: {
    rating (val) {
      // prevent rating from going out of bounds by checking it to on every change
      if (val < 0) 
        this.rating = 0
      else if (val > 5) 
        this.rating = 5

      // ... some logic to save to localStorage or somewhere else
    }
  }
})

// make sure to initialize Vue after registering all components
new Vue({
  el: document.getElementById('site-wrapper')
})

We’ll write the component template in a separate PHP file. The component will comprise six buttons (one for unrated, 5 with stars). Each button will contain an SVG with either a black or transparent fill.

<?php /* components/star-rating.php */ ?>

<star-rating inline-template>
  <div class="star-rating">
    <p>Rate recipe:</p>
    <button @click="rate(0)">
      <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
    </button>
    <button v-for="(i in 5) @click="rate(i)">
      <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
    </button>
  </div>
</star-rating>

As a rule of thumb, I like to give a component’s top element a class name that is identical to that of the component itself. This makes it easy to reason between markup and CSS (e.g. <star-rating> can be thought of as .star-rating).

And now we’ll include it in our page template.

<?php /* single-post.php */ ?>

<article class="recipe">
  <?php /* post content */ ?>

  <?php get_template_part('components/star-rating'); ?>
</article>

All the HTML inside the template is valid and understood by the browser, except for <star-rating>. We can go the extra mile to fix that by using Vue’s is directive:

<div is="star-rating" inline-template>...</div>

Now let’s say that the maximum rating isn’t necessarily 5, but is controllable by the website’s editor using Advanced Custom Fields, a popular WordPress plugin that adds custom fields for pages, posts and other WordPress content. All we need to do is inject that value as a prop of the component that we’ll call maxRating:

<?php // components/star-rating.php

// max_rating is the name of the ACF field
$max_rating = get_field('max_rating');
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>">
  <div class="star-rating">
    <p>Rate recipe:</p>
    <button @click="rate(0)">
      <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
    </button>
    <button v-for="(i in maxRating) @click="rate(i)">
      <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
    </button>
  </div>
</div>

And in our script, let’s register the prop and replace the magic number 5:

// main.js

Vue.component('star-rating', {
  props: {
    maxRating: {
      type: Number,
      default: 5 // highlight
    }
  },
  data () {
    return {
      rating: 0
    }
  },
  methods: {
    rate (i) { this.rating = i }
  },
  watch: {
    rating (val) {
      // prevent rating from going out of bounds by checking it to on every change
      if (val < 0) 
        this.rating = 0
      else if (val > maxRating) 
        this.rating = maxRating

      // ... some logic to save to localStorage or somewhere else
    }
  }
})

In order to save the rating of the specific recipe, we’ll need to pass in the ID of the post. Again, same idea:

<?php // components/star-rating.php

$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>">
  <div class="star-rating">
    <p>Rate recipe:</p>
    <button @click="rate(0)">
      <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
    </button>
    <button v-for="(i in maxRating) @click="rate(i)">
      <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
    </button>
  </div>
</div>
// main.js

Vue.component('star-rating', {
  props: {
    maxRating: { 
      // Same as before
    },
    recipeId: {
      type: String,
      required: true
    }
  },
  // ...
  watch: {
    rating (val) {
      // Same as before

      // on every change, save to some storage
      // e.g. localStorage or posting to a WP comments endpoint
      someKindOfStorageDefinedElsewhere.save(this.recipeId, this.rating)
    }
  },
  mounted () {
    this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId)    
  }
})

Now we can include the same component file in the archive page (a loop of posts), without any additional setup:

<?php // archive.php

if (have_posts()): while ( have_posts()): the_post(); ?>
<article class="recipe">
  <?php // Excerpt, featured image, etc. then:
  get_template_part('components/star-rating'); ?>
</article>
<?php endwhile; endif; ?>

The feedback form

The moment a user rates a recipe is a great opportunity to ask for more feedback, so let’s add a little form that appears right after the rating is set.

// main.js

Vue.component('feedback-form', {
  props: {
    recipeId: {
      type: String,
      required: true
    },
    show: { type: Boolean, default: false }
  },
  data () {
    return {
      name: '',
      subject: ''
      // ... other form fields
    }
  }
})
<?php // components/feedback-form.php

$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>" v-if="showForm(recipe-id)">
  <form class="recipe-feedback-form" id="feedback-form-<?= $recipe_id ?>">
    <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
    <label for="first-name-<?= $recipe_id ?>">Your name</label>
    <?php /* ... */ ?>
  </form>
</div>

Notice that we’re appending a unique string (in this case, recipe-id) to each form element’s ID. This is to make sure they all have unique IDs, even if there are multiple copies of the form on the page.

So, where do we want this form to live? It needs to know the recipe’s rating so it knows it needs to open. We’re just building good ol’ components, so let’s use composition to place the form inside the <star-rating>:

<?php // components/star-rating.php

$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>">
  <div class="star-rating">
    <p>Rate recipe:</p>
    <button @click="rate(0)">
      <svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
    </button>
    <button v-for="(i in maxRating) @click="rate(i)">
      <svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
    </button>
    <?php get_template_part('components/feedback-form'); ?>
  </div>
</div>

If at this point you’re thinking, “We really should be composing both components into a single parent component that handles the rating state,” then please give yourself 10 points and wait patiently.

A small progressive enhancement we can add to make the form usable without JavaScript, is to give it the traditional PHP action and then override it in Vue. We’ll use @submit.prevent to prevent the original action, then run a submit method to send the form data in JavaScript.

<?php // components/feedback-form.php

$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>">
  <form action="path/to/feedback-form-handler.php" 
      @submit.prevent="submit"
      class="recipe-feedback-form" 
      id="feedback-form-<?= $recipe_id ?>">
    <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
    <label for="first-name-<?= $recipe_id ?>">Your name</label>
   <!-- ... -->
  </form>
</div>

Then, assuming we want to use fetch, our submit method can be something like this:

// main.js

Vue.component('feedback-form', {
  // Same as before

  methods: {
    submit () {
      const form = this.$el.querySelector('form')
      const URL = form.action
      const formData = new FormData(form)
      fetch(URL, {method: 'POST', body: formData})
        .then(result => { ... })
        .catch(error => { ... })
    }
  }
})

OK, so what do we want to do in .then and .catch? Let’s add a component that will show real-time feedback for the form’s submit status. First let’s add the state to track sending, success, and failure, and a computed property telling us if we’re pending results.

// main.js

Vue.component('feedback-form', {
  // Same as before

  data () {
    return {
      name: '',
      subject: ''
      // ... other form fields
      sent: false,
      success: false,
​​      error: null
    }
  },
  methods: {
    submit () {
      const form = this.$el.querySelector('form')
      const URL = form.action
      const formData = new FormData(form)
      fetch(URL, {method: 'POST', body: formData})
        .then(result => { 
          this.success = true
         })
        .catch(error => { 
          this.error = error
         })
      this.sent = true
    }
  }
})

To add the markup for each message type (success, failure, pending), we could make another component like the others we’ve built so far. But since these messages are meaningless when the server renders the page, we’re better off rendering them only when necessary. To do this we’re going to place our markup in a native HTML <template> tag, which doesn't render anything in the browser. Then we’ll reference it by id as our component’s template.

<?php /* components/form-status.php */ ?>

<template id="form-status-component" v-if="false">
  <div class="form-message-wrapper">
    <div class="pending-message" v-if="pending">
      <img src="<?= get_template_directory_uri() ?>/spinner.gif">
      <p>Patience, young one.</p>
    </div>
    <div class="success-message" v-else-if="success">
      <img src="<?= get_template_directory_uri() ?>/beer.gif">
      <p>Huzzah!</p>
    </div>
    <div class="success-message" v-else-if="error">
      <img src="<?= get_template_directory_uri() ?>/broken.gif">
      <p>Ooh, boy. It would appear that: {{ error.text }}</p>
    </div>
  </div
</template>

Why add v-if="false" at the top, you ask? It’s a tricky little thing. Once Vue picks up the HTML <template>, it will immediately think of it as a Vue <template> and render it. Unless, you guessed it, we tell Vue not to render it. A bit of a hack, but there you have it.

Since we only need this markup once on the page, we’ll include the PHP component in the footer.

<?php /* footer.php */ ?>

</div> <!-- #site-wrapper -->
<?php get_template_part('components/form-status'); ?>
<?php wp_footer(); ?>

Now we’ll register the component with Vue…

// main.js

Vue.component('form-status', {
  template: '#form-status-component'
  props: {
    pending: { type: Boolean, required: true },
    success: { type: Boolean, required: true },
    error: { type: [Object, null], required: true },
  }
})

…and call it inside our form component:

<?php // components/feedback-form.php

$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>">
  <form action="path/to/feedback-form-handler.php" 
        @submit.prevent="submit"
        class="recipe-feedback-form" 
        id="feedback-form-<?= $recipe_id ?>">
    <input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
    <label for="first-name-<?= $recipe_id ?>">Your name</label>
    <?php // ... ?>
  </form>
  <form-status v-if="sent" :pending="pending" :success="success" :error="error" />
</div>

Since we registered <form-status> using Vue.component, it's available globally, without specifically including it in the parent’s components: { }.

Filtering recipes

Now that users can personalize some bits of their experience on our blog, we can add all kinds of useful functionality. Specifically, let's allow users to set a minimum rating they want to see, using an input at the top of the page.
The first thing we need is some global state to track the minimum rating set by the user. Since we started off by initializing a Vue app on the whole page, global state will just be data on the Vue instance:

// main.js
// Same as before

new Vue({
  el: document.getElementById('site-wrapper'),
  data: {
    minimumRating: 0
  }
})

And where can we put the controls to change this? Since the whole page is the app, the answer is almost anywhere. For instance, at the top of the archive page:

<?php /* archive.php */ ?>

<label for="minimum-rating-input">Only show me recipes I've rated at or above:</label>
<input type="number" id="minimum-rating-input" v-model="minimumRating">

<?php if (have_posts()): while ( have_posts()): the_post(); ?>
<article class="recipe">
  <?php /* Post excerpt, featured image, etc. */ ?>

  <?php get_template_part('components/star-rating'); ?>
</article>
<?php endwhile; endif; ?>

As long as it’s inside our site-wrapper and not inside another component, it’ll just work. If we want, we could also build a filtering component that would change the global state. And if we wanted to get all fancy, we could even add Vuex to the mix (since Vuex can’t persist state between pages by default, we could add something like vuex-persist to use localStorage).

So, now we need to hide or show a recipe based on the filter. To do this, we’ll need to wrap the recipe content in its own component, with a v-show directive. It’s probably best to use the same component for both the single page and the archive page. Unfortunately, neither require nor get_template_part can pass parameters into the called file — but we can use global variables:

<?php /* archive.php */ ?>

<label for="minimum-rating-input">Only show me recipes I've rated at or above:</label>
<input type="number" id="minimum-rating-input" v-model="minimumRating">

<?php 
$is_archive_item = true;
if (have_posts()): while ( have_posts()): the_post();
  get_template_part('components/recipe-content');
endwhile; endif; ?>

We can then use $is_archive_item as a global variable inside the PHP component file to check if it is set and true. Since we won’t need to hide the content on the single post page, we’ll conditionally add the v-show directive.

<?php  // components/recipe-content.php

global $is_archive_item; ?>
<div is="recipe-content">
  <article class="recipe" 
    <?php if ($is_archive_item): ?>
       v-show="show"
    <?php endif; ?>
  >
    <?php
    if ($is_archive_item):
      the_excerpt();
    else
      the_content();
    endif;
    
    get_template_part('components/star-rating');
    ?>
  </article>
</div>

In this specific example, we could have also tested with  is_archive() inside the component, but in most cases we’ll need to set explicit props.

We’ll need to move the rating state and logic up into the <recipe-content> component so it can know if it needs to hide itself. Inside <star-rating>, we’ll make a custom v-model by replacing rating with value, and this.rating = i with  $emit('input', i) as well . So our component registration will now look like this:

// main.js

Vue.component('recipe-content', {
  data () {
    rating: 0
  },
  watch: {
    rating (val) {
      // ...
    }
  },
  mounted () {
    this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId)    
  }
})

Vue.component('star-rating', {
  props: {
    maxRating: { /* ... */ },
    recipeId: { /* ... */ },
    value: { type: Number, required: true }
  },
  methods: {
    rate (i) { this.$emit('input', i) }
  },
})

We’ll add v-model in star-rating.php and change rating to value. In addition, we can now move the <feedback-form> up into <recipe-content>:

<?php // components/star-rating.php

$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating" 
  inline-template 
  :max-rating="<?= $ max_rating ?>" 
  recipe-id="<?= $recipe_id ?>" 
  v-model="value"
>
  <div class="star-rating">
    <p>Rate recipe:</p>
    <button @click="rate(0)">
      <svg><path d="..." :fill="value === 0 ? 'black' : 'transparent'"></svg>
    </button>
    <button v-for="(i in maxRating) @click="rate(i)">
      <svg><path d="..." :fill="value >= i ? 'black' : 'transparent'"></svg>
    </button>
  </div>
</div>
<?php // components/recipe-content.php

global $is_archive_item; ?>
<div is="recipe-content">
  <article class="recipe" 
    <?php if ($is_archive_item): ?>
       v-show="show"
    <?php endif; ?>
  >
    
    <?php
    if ($is_archive_item):
      the_excerpt();
    else
      the_content();
    endif;
    
    get_template_part('components/star-rating');
    get_template_part('components/feedback-form');
    ?>
  </article>
</div>

Now everything is set up so the initial render shows all recipes, and then the user can filter them based on their rating. Moving forward, we could add all kinds of parameters to filter content. And it doesn’t have to be based on user input — we can allow filtering based on the content itself (e.g. number of ingredients or cooking time) by passing the data from PHP to Vue.

Conclusion

Well, that was a bit of a long ride, but look at what we’ve built: independent, composable, maintainable, interactive, progressively enhanced components in our WordPress theme. We brought together the best of all worlds!

I’ve been using this approach in production for a while now, and I love the way it allows me to reason about the different parts of my themes. I hope I’ve inspired you to try it out too.


  1. Of course, two days before launch, the client’s legal department decided they don't want to collect all that info. Currently the live form is but a shadow of its development self.
  2. Fun fact: Rasmus Lerdorf said that his original intent was for PHP to be templating only, with all business logic handled in C. Let that sink in for a moment. Then clear an hour from your schedule and watch the whole talk.
  3. There are third-party WordPress templating engines that can compile down to optimized PHP. Twig, for example, comes to mind. We’re trying to go the reverse route and send vanilla PHP to be handled by JavaScript.

The post How to Build Vue Components in a WordPress Theme appeared first on CSS-Tricks.

15:27

Web Component for a Code Block

We'll get to that, but first, a long-winded introduction.

I'm still not in a confident place knowing a good time to use native web components. The templating isn't particularly robust, so that doesn't draw me in. There is no state management, and I like having standard ways of handling that. If I'm using another library for components anyway, seems like I would just stick with that. So, at the moment, my checklist is something like:

  • Not using any other JavaScript framework that has components
  • Templating needs aren't particularly complex
  • Don't need particularly performant re-rendering
  • Don't need state management

I'm sure there is tooling that helps with these things and more (the devMode episode with some folks from Stencil was good), but if I'm going to get into tooling-land, I'd be extra tempted to go with a framework, and probably not framework plus another thing with a lot of overlap.

The reasons I am tempted to go with native web components are:

  • They are native. No downloads of frameworks.
  • The Shadow DOM is a true encapsulation in a way a framework can't really do.
  • I get to build my own HTML element that I use in HTML, with my own API design.

It sorta seems like the sweet spot for native web components is design system components. You build out your own little API for the components in your system, and people can use them in a way that is a lot safer than just copy and paste this chunk of HTML. And I suppose if consumers of the system wanted to BYO framework, they could.

So you can use like <our-tabs active-tab="3"> rather than <div class="tabs"> ... <a href="#3" class="tab-is-active">. Refactoring the components certainly gets a lot easier as changes percolate everywhere.

I've used them here on CSS-Tricks for our <circle-text> component. It takes the radius as a parameter and the content via, uh, content, and outputs an <svg> that does the trick. It gave us a nice API for authoring that abstracted away the complexity.

So!

It occurred to me a "code block" might be a nice use-case for a web component.

  • The API would be nice for it, as you could have attributes control useful things, and the code itself as the content (which is a great fallback).
  • It doesn't really need state.
  • Syntax highlighting is a big gnarly block of CSS, so it would be kinda cool to isolate that away in the Shadow DOM.
  • It could have useful functionality like a "click to copy" button that people might enjoy having.

Altogether, it might feel like a yeah, I could use this kinda component.

This probably isn't really production ready (for one thing, it's not on npm or anything yet), but here's where I am so far:

CodePen Embed Fallback

Here's a thought dump!

  • What do you do when a component depends on a third-party lib? The syntax highlighting here is done with Prism.js. To make it more isolated, I suppose you could copy and paste the whole lib in there somewhere, but that seems silly. Maybe you just document it?
  • Styling web components doesn't feel like it has a great story yet, despite the fact that Shadow DOM is cool and useful.
  • Yanking in pre-formatted text to use in a template is super weird. I'm sure it's possible to do without needing a <pre> tag inside the custom element, but it's clearly much easier if you grab the content from the <pre>. Makes the API here just a smidge less friendly (because I'd prefer to use the <code-block> alone).
  • I wonder what a good practice is for passing along attributes that another library needs. Like is data-lang="CSS" OK to use (feels nicer), and then convert it to class="language-css" in the template because that's what Prism wants? Or is it better practice to just pass along attributes as they are? (I went with the latter.)
  • People complain that there aren't really "lifecycle methods" in native web components, but at least you have one: when the thing renders: connectedCallback. So, I suppose you should do all the manipulation of HTML and such before you do that final shadowRoot.appendChild(node);. I'm not doing that here, and instead am running Prism over the whole shadowRoot after it's been appended. Just seemed to work that way. I imagine it's probably better, and possible, to do it ahead of time rather than allow all the repainting caused by injecting spans and such.
  • The whole point of this is a nice API. Seems to me thing would be nicer if it was possible to drop un-escaped HTML in there to highlight and it could escape it for you. But that makes the fallback actually render that HTML which could be bad (or even theoretically insecure). What's a good story for that? Maybe put the HTML in HTML comments and test if <!-- is the start of the content and handle that as a special situation?

Anyway, if you wanna fork it or do anything fancier with it, lemme know. Maybe we can eventually put it on npm or whatever. We'll have to see how useful people think it could be.

The post Web Component for a Code Block appeared first on CSS-Tricks.

14:15
6 Amazing Packaging Design Ideas for 2020 That Are on Point
13:41
The 40+ Web Tools And Services That Everybody Is Using Daily
11:31
Inventory Management
11:00

How To Make Cross-Browser Testing More Efficient With LambdaTest

How To Make Cross-Browser Testing More Efficient With LambdaTest

How To Make Cross-Browser Testing More Efficient With LambdaTest

Suzanne Scacca
2020-02-18T11:00:00+00:002020-02-18T18:36:51+00:00

Before consumers sat in front of mobile devices for hours every day, there were numerous browsers and operating systems web designers had to contend with. So, it’s not like the concept of cross-browser testing is new.

Because web browsers don’t always render websites the same way or process data in the manner originally intended, cross-browser testing has long been an important part of web design and development. It’s the only way to ensure that what’s built behind the scenes is properly implemented on the frontend of a website.

But it can quickly become a tedious undertaking if you attempt to review every browser, OS and device on your own.

Fortunately, we’re living in an era where automation is king and we now have a better way of conducting cross-browser tests (and more frequently, too). So, let’s talk about why you need to automate this process and how to do so with the help of LambdaTest.

An Improved Way To Handle Cross-Browser Testing

When you set out to build a website for your users, you account for who they are, what they need and what they will respond to along their journey. But how and when do you address the different outcomes your users might experience thanks to their browser choice?

Responsive design may help mitigate some of these differences, but it’s not a cure-all for the inherent display issues between browsers and devices.

To fully ensure that the code and design choices you’ve made for a website won’t negatively impact users, cross-browser testing throughout the web design process is essential.

And if you want to make sure extensive cross-browser testing doesn’t have a negative impact on your bottom line, then automating it is the way to go.

Here are some tips to help you build automated testing into your process:

Familiarize Yourself With Browser Support Differences

This is a roundup from Statista of the top web browsers by market share:

Statista - top web and mobile browsers 2020 Statista data on the top web and mobile browsers in 2020. (Source: Statista) (Large preview)

Now, the issue here isn’t necessarily that every browser processes your website data differently. What’s really mucking things up is the engine powering the browser behind the scenes.

For example, these are the engines the leading web browsers use:

  • Chrome uses Blink + V8;
  • Edge uses Blink;
  • Firefox uses Quantum/Gecko + SpiderMonkey;
  • Safari uses WebKit + Nitro;
  • Internet Explorer uses Trident + Chakra.

Many of these engines render the same piece of code differently. For example, look at this experiment created by LambdaTest:

LambdaTest Experiment - date time format in Chrome A LambdaTest Experiment shows how the Chrome browser displays this code snippet. (Source: LambdaTest) (Large preview)

The date HTML tag is one of the most used tags and, yet, Chrome, Firefox and Opera are the only ones that fully support it — as indicated in the top blue bar above the test area. Even then, these browsers provide very different user experiences.

For example, the image above shows you what the date tag looks like in Chrome. Here’s how the same code displays in Edge:

LambdaTest Experiment - date time format in Edge A LambdaTest Experiment shows how the Edge browser displays this code snippet. (Source: LambdaTest) (Large preview)

Not only does the font styling and sizing slightly different, but the way in which the date selection dropdown appears is vastly different.

So, before you start thinking about cross-browser testing and hammering out the kinks between these browsers and engines, familiarize yourself with the key differences.

A tool you can use as reference is Can I use….

You can look for discrepancies in the most commonly used components and technologies. Take, for instance, CSS grid layout:

Can I use… - CSS Grid Layout browser compatibility Can I use… keeps track of cross-browser compatibility for CSS Grid Layout. (Source: Can I use…) (Large preview)

Most of the leading (and some not so leading) browsers support CSS grid layout (the ones in green). Internet Explorer (in blue) provides partial support and Opera Mini (in purple) provides none at all.

Or let’s say you’re trying to use more WebP images in your designs as they’re much better for performance and resolution. Here’s what Can I use… tells us about browser support for the image format:

Can I use… - WebP image format browser compatibility Can I use… data on cross-browser support for the WebP image format. (Source: Can I use…) (Large preview)

The most recent versions of Internet Explorer and Safari (web and mobile) do not provide support for it. So, if you intend on designing with WebP images, you’ll have to create a workaround for these browsers.

Bottom line: Take the time now to understand what kind of content or code is supported, so you can more effectively build a website from the get-go.

Pro Tip: Create a Browser Matrix for Reference

You can see why it’s so important to understand the differences between browser renderings and support. The more you familiarize yourself with them, the less scrambling you’ll have to do when a new discrepancy is discovered.

To make it easier on yourself, it would be a good idea to create a browser matrix for all these differences now.

Here’s a simple one that LambdaTest has designed:

Web browser support matrix example An example of how web designers can create their own browser support matrices. (Source: LambdaTest) (Large preview)

I’d recommend creating one of your own. You can leverage data from Can I use… as well as documenting support issues you’ve encountered in your own projects.

This will also help you set priorities when you’re designing. For example, you can decide which non-supported features are worth using based on what kind of impact they have on your website’s goals.

It would also be useful to have this spreadsheet on hand once a site has gone live. Using data from Google Analytics, you can start prioritizing design choices based on which web browsers your users primarily use.

Get Yourself A Cross-Browser Testing Tool That Does It All

It doesn’t matter the size of the websites you build. All public-facing sites would benefit from an automated cross-browser testing tool.

What’s especially nice about automating with LambdaTest is that it gives its users options. From fully automated tests that check how your code impacts the frontend to semi-automated tasks that ease the work in managing updates and bugs, there are so many ways to automate and optimize your process.

Here are some of the feature highlights you should know about:

Real Time Testing: Best for Bug Tracking

Real-time testing is useful when there’s something targeted you need to examine with your own two eyes. Like if you’ve shipped a design to the client for review and they insist something doesn’t look right on their end, you can review the website using their exact configuration. It would also be helpful for confirming bugs and sussing out which browsers are impacted.

From the Real-Time Testing panel, you’ll enter your site URL and then choose your viewing specifications.

It lets you get super specific, choosing from:

  • Mac vs. Android,
  • Device type,
  • Device version,
  • Operating system,
  • Web browser.
LambdaTest - Real Time Testing This is the LambdaTest dashboard area for Real Time Testing. (Source: LambdaTest) (Large preview)

Once the test begins, this is what you’ll see (depending on the type of device you choose, of course):

Real Time Testing with LambdaTest A Real Time Test conducted by LambdaTest. (Source: LambdaTest) (Large preview)

Above, you can see the first option in the sidebar enables you to quickly switch the device view. That way, if you have a couple of browser views you’re trying to compare or check errors on, you don’t have to backtrack.

As far as the other real-time testing options go, most of them are useful for identifying and reporting issues within the context that they actually happened.

LambdaTest bug tracking LambdaTest’s Real Time Testing can be used for bug tracking and reporting. (Source: LambdaTest) (Large preview)

In the bug tracking tool above, you can pinpoint a spot on the page where an error has occurred. You can then mark it up using a number of tools on the sidebar.

Users can also use the screenshotting and video options to capture bigger errors — especially ones that occur when you move through or engage with the site.

Screenshot Testing: Best for Speeding Up Manual Testing

There’s no reason you or your QA can’t still review your website on your own. That said, why make the process take longer than it needs to? You can let LambdaTest’s Visual UI Testing tools speed up the process.

The Screenshot tool, for instance, enables you to select all of the devices and browsers you want to compare at once:

LambdaTest simultaneous screenshottin LambdaTest Visual UI Testing comes with simultaneous cross-browser screenshotting. (Source: LambdaTest) (Large preview)

When the test completes, you’ll have all requested screenshots in one place:

Lambdatest screenshot check for inconsistencies LambdaTest screenshots enable designers to quickly check for inconsistencies across browsers. (Source: LambdaTest) (Large preview)

You can view them here, download them to your computer or share them with others.

You can also organize your screenshots by project and version/round. That way, if you’re working through multiple rounds of revisions and want to refer back to a previous version, all copies of the previous iteration exist here. (You can also use screenshots in regression testing which I’ll explain shortly.)

Responsive Testing: Best for Confirming a Mobile-first Experience

If you need to see more than just a static screengrab, Responsive tests have you covered. All you need to do is select which OS and devices you want to compare and the tool will populate full working versions of the site in the mobile browser:

LambdaTest responsive testing LambdaTest includes real-time responsive tests for all OS and devices. (Source: LambdaTest) (Large preview)

You can review your website’s design and interactivity not just in all possible browsers, but you can change the orientation of the site as well (in case issues appear when it goes landscape).

What’s nice about this testing tool is that, if anything appears wonky, you can mark the bug the second you detect it. There’s a button for you to do that directly above the interactive mobile browser. That'll get those costly mobile errors reported and resolved more quickly.

Smart Testing: Best for Regression Testing

The eye can only detect so much, especially when you’ve been looking at the same section of a web page for weeks.

So, when you start implementing changes on your site — during development, just prior to launch and even afterwards — regression testing is going to be crucial for catching those potentially hard-to-spot issues.

This should take place any time something changes:

  • You manually update part of the design.
  • Code is tweaked on the backend.
  • Someone reports a bug and the fix is implemented.
  • Software is updated.
  • An API is reconnected.

If you know which page and which part of that page are directly impacted, smart testing can make light work of confirming that everything is okay.

Just upload the original screenshot of the impacted page and then add a comparison image when the change has been made. (This is where that Screenshot tool really comes in handy.)

LambdaTest Smart Testing LambdaTest enables users to do side-by-side comparison tests of web pages. (Source: LambdaTest) (Large preview)

Note: There’s obviously nothing wrong with the Smashing Magazine website. But what I did in the example above is use renderings for different versions of the iPhone. Obviously, that’s not how regression tests work, but I wanted to show you how this comparison feature looks when something’s amiss.

Now, as for why this feature is so awesome, here’s how it works:

LambdaTest layered comparison LambdaTest users can compare two versions of the same web layered on top of one another. (Source: LambdaTest) (Large preview)

This single screenshot allows you to see where the two versions of your page no longer align. So, if the screenshots had been from the same browser view originally, this could be a problem if you hadn’t planned on realigning all of the elements.

You could also use the side-by-side comparison tests to check the same thing:

LambdaTest side-by-side comparison LambdaTest users can compare two versions of the same web page side-by-side. (Source: LambdaTest) (Large preview)

Again, smart testing is meant to help you quickly locate and report issues during regression testing. Find the method that works best for you, so you can get these issues resolved as quickly as possible from now on.

Automated Testing: Best for Detecting Issues on a Larger Scale

Technically, everything we’ve looked at so far has some form of automation built in, whether it’s processing 20 different browser screenshots simultaneously or letting you instantly see mobile test interfaces for all iOS and Android devices at once.

That said, the LambdaTest platform also comes with a tool called “Automation”. And what this does is enable you to do Selenium testing in the cloud on over 2,000 browsers. A newer feature, “Lambda Tunnel”, can be used to do Selenium testing on your localhost as well. That way, you can see how your code changes appear even before they go live.

There are tons of benefits to combining LambdaTest with Selenium testing:

  • It’s a highly efficient way to conduct large quantities of cross-browser tests, thereby increasing your browser coverage (something that’s impossible to do manually).
  • With parallel cross-browser tests, you’ll reduce the time spent executing automation tests as a whole.
  • Because Selenium testing starts by identifying your preferred coding language, it can more intelligently detect errors that will appear in browsers.

Of course, the biggest benefit of using the LambdaTest Selenium Automation Grid is that LambdaTest will help you evaluate whether or not your tests pass or fail.

LambdaTest Automated Test (Build View) LambdaTest can help users qualify cross-browser tests as failures when errors are detected. (Source: LambdaTest) (Large preview)

You still have to review the results to confirm that all errors are true failures and vice versa, but it’s going to save you a lot of time and headaches having LambdaTest do the initial work for you.

Wrapping Up

Cross-browser testing isn’t just about making sure websites are mobile responsive. What we’re ultimately looking to do here is take the guesswork out of web design. There may be over a dozen possible browsers and hundreds of browser/device configurations, but automated cross-browser tests can make checking all of these possibilities and locating errors much easier.

Smashing Editorial(ms, ra, yk, il)
00:07

A Complete Guide to Data Attributes

Introduction

HTML elements can have attributes on them that are used for anything from accessibility information to stylistic control.

<!-- We can use the `class` for styling in CSS, and we've also make this into a landmark region -->
<div class="names" role="region" aria-label="Names"></div>

What is discouraged is making up your own attributes, or repurposing existing attributes for unrelated functionality.

<!-- `highlight` is not an HTML attribute -->
<div highlight="true"></div>

<!-- `large` is not a valid value of `width` -->
<div width="large">

There are a variety of reasons this is bad. Your HTML becomes invalid, which may not have any actual negative consequences, but robs you of that warm fuzzy valid HTML feeling. The most compelling reason is that HTML is a living language and just because attributes and values that don't do anything today doesn't mean they never will.

Good news though: you can make up your own attributes. You just need to prefix them with data-* and then you're free to do what you please!

Syntax

It can be awfully handy to be able to make up your own HTML attributes and put your own information inside them. Fortunately, you can! That's exactly what data attributes are. They are like this:

<!-- They don't need a value -->
<div data-foo></div>

<!-- ...but they can have a value -->
<div data-size="large"></div>

<!-- You're in HTML here, so careful to escape code if you need to do something like put more HTML inside -->
<li data-prefix="Careful with HTML in here."><li>

<!-- You can keep dashing if you like -->
<aside data-some-long-attribute-name><aside>

Data attributes are often referred to as data-* attributes, as they are always formatted like that. The word data, then a dash -, then other text you can make up.

Can you use the data attribute alone?

<div data=""></div>

It's probably not going to hurt anything, but you won't get the JavaScript API we'll cover later in this guide. You're essentially making up an attribute for yourself, which as I mentioned in the intro, is discouraged.

What not to do with data attributes

Store content that should be accessible. If the content should be seen or read on a page, don't only put them in data attributes, but make sure that content is in the HTML content somewhere.

<!-- This isn't accessible content -->
<div data-name="Chris Coyier"></div>

<!-- If you need programmatic access to it but shouldn't be seen, there are other ways... -->
<div>
  <span class="visually-hidden">Chris Coyier</span>
</div>

Here's more about hiding things.

Styling with data attributes

CSS can select HTML elements based on attributes and their values.

/* Select any element with this data attribute and value */
[data-size="large"] {
  padding: 2rem;
  font-size: 125%;
}

/* You can scope it to an element or class or anything else */
button[data-type="download"] { }
.card[data-pad="extra"] { }

This can be compelling. The predominant styling hooks in HTML/CSS are classes, and while classes are great (they have medium specificity and nice JavaScript methods via classList) an element either has it or it doesn't (essentially on or off). With data-* attributes, you get that on/off ability plus the ability to select based on the value it has at the same specificity level.

/* Selects if the attribute is present at all */
[data-size] { }

/* Selects if the attribute has a particular value */
[data-state="open"],
[aria-expanded="true"] { }

/* "Starts with" selector, meaning this would match "3" or anything starting with 3, like "3.14" */
[data-version^="3"] { }

/* "Contains" meaning if the value has the string anywhere inside it */
[data-company*="google"] { }

The specificity of attribute selectors

It's the exact same as a class. We often think of specificity as a four-part value:

inline style, IDs, classes/attributes, tags

So a single attribute selector alone is 0, 0, 1, 0. A selector like this:

div.card[data-foo="bar"] { }

...would be 0, 0, 2, 1. The 2 is because there is one class (.card) and one attribute ([data-foo="bar"]), and the 1 is because there is one tag (div).

Attribute selectors have less specificity than an ID, more than an element/tag, and the same as a class.

Case-insensitive attribute values

In case you're needing to correct for possible capitalization inconsistencies in your data attributes, the attribute selector has a case-insensitive variant for that.

/* Will match
<div data-state="open"></div>
<div data-state="Open"></div>
<div data-state="OPEN"></div>
<div data-state="oPeN"></div>
*/
[data-state="open" i] { }

It's the little i within the bracketed selector.

Using data attributes visually

CSS allows you to yank out the data attribute value and display it if you need to.

/* <div data-emoji="✅"> */

[data-emoji]::before {
  content: attr(data-emoji); /* Returns '✅' */
  margin-right: 5px;
}

Example styling use-case

You could use data attributes to specify how many columns you want a grid container to have.

<div data-columns="2"></div>
<div data-columns="3"></div>
<div data-columns="4"></div>
CodePen Embed Fallback

Accessing data attributes in JavaScript

Like any other attribute, you can access the value with the generic method getAttribute.

let value = el.getAttribute("data-state");

// You can set the value as well.
// Returns data-state="collapsed"
el.setAttribute("data-state", "collapsed");

But data attributes have their own special API as well. Say you have an element with multiple data attributes (which is totally fine):

<span 
  data-info="123" 
  data-index="2" 
  data-prefix="Dr. "
  data-emoji-icon="🏌️‍♀️"
></span>

If you have a reference to that element, you can set and get the attributes like:

// Get
span.dataset.info; // 123
span.dataset.index; // 2

// Set
span.dataset.prefix = "Mr. ";
span.dataset.emojiIcon = "🎪";

Note the camelCase usage on the last line there. It automatically converts kebab-style attributes in HTML, like data-this-little-piggy, to camelCase style in JavaScript, like dataThisLittlePiggy.

This API is arguably not quite as nice as classList with the clear add, remove, toggle, and replace methods, but it's better than nothing.

You have access to inline datasets as well:

<img src="spaceship.png"
  data-ship-id="324" data-shields="72%"
  onclick="pewpew(this.dataset.shipId)">
</img>

JSON data inside data attributes

<ul>
  <li data-person='
    {
      "name": "Chris Coyier",
      "job": "Web Person"
    }
  '></li>
</ul>

Hey, why not? It's just a string and it's possible to format it as valid JSON (mind the quotes and such). You can yank that data and parse it as needed.

const el = document.querySelector("li");

let json = el.dataset.person;
let data = JSON.parse(json);

console.log(data.name); // Chris Coyier
console.log(data.job); // Web Person

JavaScript use-cases

The concept is that you can use data attributes to put information in HTML that JavaScript may need access to do certain things.

A common one would have to do with database functionality. Say you have a "Like" button:

<button data-id="435432343">♡</button>

That button could have a click handler on it which performs an Ajax request to the server to increment the number of likes in a database on click. It knows which record to update because it gets it from the data attribute.

Specifications

Browser support

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

Desktop

Chrome Firefox IE Edge Safari 7 6 11 12 5.1

Mobile / Tablet

Android Chrome Android Firefox Android iOS Safari 79 68 3 5.0-5.1

The post A Complete Guide to Data Attributes appeared first on CSS-Tricks.

February 17 2020

15:59
What are the Top 7 PHP IDEs and Code Editors a Web Developer Uses?
15:42

Moving from Vanilla JavaScript to a Reusable Vue Component

I recently wrote an article explaining how you can create a countdown timer using HTML, CSS and JavaScript. Now, let’s look at how we can make that a reusable component by porting it into Vue using basic features that the framework provides.

Why do this at all? Well there are few reasons, but two stand out in particular:

  • Keeping UI in sync with the timer state: If you look at the code from the first post,  it all lives in the timerInterval function, most noticeably the state management. Each time it runs (every second) we need to manually find the proper element on our document — whether it’s the time label or the remaining time path or whatever — and change either its value or an attribute. Vue comes with an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. That takes all the burden of finding and updating proper UI elements so we can rely purely on the component instance’s properties.
  • Having a highly reusable component: The original example works fine when only one timer is present on our document, but imagine that you want to add another one. Oops! We rely the element’s ID to perform our actions and using the same ID on multiple instances would prevent them from working independently. That means we would have to assign different IDs for each timer. If we create a Vue component, all it’s logic is encapsulated and connected to that specific instance of the component. We can easily create 10, 20, 1,000 timers on a single document without changing a single line in the component itself!

Here’s the same timer we created together in the last post, but in Vue.

Template and styles

From the Vue docs:

Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying Vue instance’s data. All Vue.js templates are valid HTML that can be parsed by spec-compliant browsers and HTML parsers.

Let’s create our component by opening a new file called BaseTimer.vue. Here’s the basic structure we need for that:

// Our template markup will go here
<template>
// ...
</template>

// Our functional scripts will go here
<script>
// ...
</script>

// Our styling will go here
<style>
// ...
</style>

In this step, we will concentrate on the <template> and <style> sections. Let’s move our timer template to the <template> section and all our CSS to <style> section. The markup mostly consists of SVG and we can use the exact same code we used from the first article.

<template>
  // The wrapper for the timer
  <div class="base-timer">

    // This all comes from the first article
    <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      <g class="base-timer__circle">
        <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle>
        <path
          id="base-timer-path-remaining"
          stroke-dasharray="283"
          class="base-timer__path-remaining ${remainingPathColor}"
          d="
            M 50, 50
            m -45, 0
            a 45,45 0 1,0 90,0
            a 45,45 0 1,0 -90,0
          "
        ></path>
      </g>
    </svg>

    // The label showing the remaining time
    <span
      id="base-timer-label"
      class="base-timer__label"
    >
      ${formatTime(timeLeft)}
    </span>

  </div>
</template>

// "scoped" means these styles will not leak out to other elements on the page
<style scoped>
.base-timer {
  position: relative;
  width: 100px;
  height: 100px;
}
</style>

Let’s have a look at the template we just copied to identify where we can use our framework. There are few parts that are responsible for making our timer count down the time and show the remaining time.

  • stroke-dasharray: A value passed to the SVG <path> element that is responsible for holding the remaining time.
  • remainingPathColor: A CSS class responsible for changing the color of the timer’s circular ring, giving is a way to visually indicate that time is running out.
  • formatTime(timeLeft): A value responsible for showing how much time is left inside the timer

We can control our timer by manipulating those values.

Constants and variables

OK, let’s go down to our <script> section and see what Vue gives us out of the box to make our life easier. One thing it lets us do is define our constants up front, which keeps them scoped to the component.

In the last post, we spent a little time tweaking the stroke-dasharray  value to make sure the animation of the timer’s top layer (the ring that animates and changes color as time progresses) is perfectly in line with its bottom layer (the gray ring that indicates past time). We also defined “thresholds” for when the top layer should change colors (orange at 10 remaining seconds and red at five seconds). We also created constants for those colors.

We can move all of those directly into the <script> section:

<script>
// A value we had to play with a bit to get right
const FULL_DASH_ARRAY = 283;
// When the timer should change from green to orange
const WARNING_THRESHOLD = 10;
// When the timer should change from orange to red
const ALERT_THRESHOLD = 5;

// The actual colors to use at the info, warning and alert threshholds
const COLOR_CODES = {
  info: {
    color: "green"
  },
  warning: {
    color: "orange",
    threshold: WARNING_THRESHOLD
  },
  alert: {
    color: "red",
    threshold: ALERT_THRESHOLD
  }
};

// The timer's starting point
const TIME_LIMIT = 20;
</script>

Now, let’s have a look at our variables:

let timePassed = 0;
let timeLeft = TIME_LIMIT;
let timerInterval = null;
let remainingPathColor = COLOR_CODES.info.color;

We can identify two different types of variables here:

  1. Variables in which the values are directly re-assigned in our methods:
    • timerInterval: Changes when we start or stop the timer
    • timePassed: Changes each second when the timer is running
  2. Variables in which the values change when other variables change:
    • timeLeft: Changes when the value of timePassed changes
    • remainingPathColor: Changes when the value of timeLeft breaches the specified threshold

It is essential to identify that difference between those two types as it allows us to use different features of the framework. Let’s go through each of the type separately.

Variables in which values are directly re-assigned

Let’s think what we want to happen when we change the timePassed value. We want to calculate how much time is left, check if we should change the top ring’s color, and trigger re-render on a part of our view with new values. 

Vue comes with its own reactivity system that updates the view to match the new values of specific properties. To add a property to Vue’s reactivity system we need to declare that property on a data object in our component. By doing that,Vue will create a getter and a setter for each property that will track changes in that property and respond accordingly.

<script>
// Same as before

export default {
  data() {
    return {
      timePassed: 0,
      timerInterval: null
    };
  }
</script>

There are two important things we need to remember.

  1. We need to declare all reactive variables in our data object up front. That means if we know that a variable will exist but we don’t know what the value will be, we still need to declare it with some value. If we forgot to declare it in data it will not be reactive, even if it is added later.
  2. When declaring our data option object, we always need to return a new object instance (using return). This is vital because, if we don’t follow this rule, the declared properties will be shared between all instances of the component.

You can see that second issue in action:

Variables in which values change when other variable change

These variables rely on the value of another variable. For example, timeLeft relies purely on timePassed. In our original example that uses vanilla JavaScript, we were calculating that value in the interval that was responsible for changing the value of timePassed. With Vue, we can extract that value to a computed property.

computed property is a function that returns a value. These values are bound to the dependency values and only update when required. Even more importantly, computed properties are cached, meaning they remember the values that the computed property depends on and calculate the new value only if that dependent property value changed. If the value does not change, the previously cached value is returned.

<script>
// Same as before

computed: {
    timeLeft() {
      return TIME_LIMIT - this.timePassed;
    }
  }
}
</script>

The function passed to the computed property must be a pure function. It can’t cause any side effects and must return a value. Also, the output value must only be dependent on the values passed into the function.

Now, we can move more logic to computed properties:

  • circleDasharray: This returns a value previously that is calculated in the setCircleDasharray method.
  • formattedTimeLeft: This returns a value from the formatTime method.
  • timeFraction: This is an abstraction of the calculateTimeFraction method.
  • remainingPathColor: This is an abstraction of the setRemainingPathColor method.
<script>
// Same as before

computed: {
    circleDasharray() {
      return `${(this.timeFraction * FULL_DASH_ARRAY).toFixed(0)} 283`;
    },

    formattedTimeLeft() {
      const timeLeft = this.timeLeft;
      const minutes = Math.floor(timeLeft / 60);
      let seconds = timeLeft % 60;
      if (seconds < 10) {
        seconds = `0${seconds}`;
      }
      return `${minutes}:${seconds}`;
    },

    timeLeft() {
      return TIME_LIMIT - this.timePassed;
    },

    timeFraction() {
      const rawTimeFraction = this.timeLeft / TIME_LIMIT;
      return rawTimeFraction - (1 / TIME_LIMIT) * (1 - rawTimeFraction);
    },

    remainingPathColor() {
      const { alert, warning, info } = COLOR_CODES;
      if (this.timeLeft <= alert.threshold) {
        return alert.color;
      } else if (this.timeLeft <= warning.threshold) {
        return warning.color;
      } else {
        return info.color;
      }
    }
  }
</script>

We now have all the values we need! But now we need to put them to use in our template.

Using data and computed properties in the template

Here’s where we left off with our template:


<template>
  <div class="base-timer">
    <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      <g class="base-timer__circle">
        <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle>
        <path
          id="base-timer-path-remaining"
          stroke-dasharray="283"
          class="base-timer__path-remaining ${remainingPathColor}"
          d="
            M 50, 50
            m -45, 0
            a 45,45 0 1,0 90,0
            a 45,45 0 1,0 -90,0
          "
        ></path>
      </g>
    </svg>
    <span
      id="base-timer-label"
      class="base-timer__label"
    >
        ${formatTime(timeLeft)}
    </span>
  </div>
</template>

Let’s start with formatTime(timeLeft). How we can dynamically bind the rendered value to our formattedTimeLeftcomputed property?

Vue uses HTML-based template syntax that allowsus to declaratively bind the rendered DOM to the underlying data of the Vue instance. That means all properties are available in the template section. To render any of them, we use text interpolation using the “Mustache” syntax (double curly braces, or {{ }}).

<span
  id="base-timer-label"
  class="base-timer__label"
>
  {{ formattedTimeLeft }} 
</span>

Next will be stroke-dasharray. We can see we don’t want to render that value. Instead, we want to change the value of the <path> attribute. Mustache cannot be used inside HTML attributes, but fear not! Vue comes with another way: the v-bind directive. We can bind a value to an attribute like this:

<path  v-bind:stroke-dasharray="circleDasharray"></path>

To facilitate the usage of that directive, we can also use a shorthand.

<path  :stroke-dasharray="circleDasharray"></path>

The last one is remainingPathColor, which adds a proper class to an element. We can do that using the same v-bind directive as above, but assign the value to the class attribute of an element.

<path  :class="remainingPathColor"></path>

Let’s have a look at our template after changes.

<template>
  <div class="base-timer">
    <svg class="base-timer__svg" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
      <g class="base-timer__circle">
        <circle class="base-timer__path-elapsed" cx="50" cy="50" r="45"></circle>
        <path
          :stroke-dasharray="circleDasharray"
          class="base-timer__path-remaining"
          :class="remainingPathColor"
          d="
            M 50, 50
            m -45, 0
            a 45,45 0 1,0 90,0
            a 45,45 0 1,0 -90,0
          "
        ></path>
      </g>
    </svg>
    <span class="base-timer__label">{{ formattedTimeLeft }}</span>
  </div>
</template>

We have our template ready, we moved all variables to data or computed, and we got rid off most of the methods by creating corresponding computed properties. We are still missing one vital part, though: we need to start our timer.

Methods and component lifecycle hooks

If we look at our startTimer method, we can see that all the calculations, changes in attributes, etc. happen in the interval.

function startTimer() {
  timerInterval = setInterval(() => {
    timePassed = timePassed += 1;
    timeLeft = TIME_LIMIT - timePassed;
    document.getElementById("base-timer-label").innerHTML = formatTime(
      timeLeft
    );
    setCircleDasharray();
    setRemainingPathColor(timeLeft);
    if (timeLeft === 0) {
      onTimesUp();
    }
  }, 1000);
}

Since we’ve already moved all that logic into the computed property, all we need to do in our timerInterval is change the value of timePassed — the rest will happen magically in the computed properties

<script>
// Same as before

methods: {
  startTimer() {
    this.timerInterval = setInterval(() => (this.timePassed += 1), 1000);
  }
}
</script>

We have the method ready, but we still don’t call it anywhere. Each Vue component comes with a series of hooks that allows us to run a specific logic within a specific period of the component’s lifecycle. These are called lifecycle hooks. In our case, as we want to call our method immediately when the component gets loaded. That makes mounted the lifecycle hook what we want.

<script>
// Same as before

mounted() {
  this.startTimer();
},

// Same methods as before
</script> 

That’s it, we just turned our timer into a consistent and reusable component using Vue!

Let's say we now want to use this component in another component. That requires a few things:

  1. First, we import the component.
  2. Next, we register the component.
  3. Finally, we instantiate the component in the template.
// App.vue

import BaseTimer from "./components/BaseTimer"

export default {
  components: {
    BaseTimer
  }
};

That’s a wrap!

This example shows how we can move a component from vanilla JavaScript to a component-based front-end framework, like Vue. 

We can now treat the timer as a standalone component where all the markup, logic and styling is contained in a way that won’t leak out to or conflict with other elements. Components are often children of a larger parent component that assembles multiple components together — like a form or perhaps a card — where the parent’s properties can be accessed and shared. Here’s an example of the timer component where it’s taking orders from a parent component

I hope I got you interested in Vue and the power of components! I’d encourage you to go to Vue docs to get more detailed description of the features we used in our example. There’s so much Vue can do!

The post Moving from Vanilla JavaScript to a Reusable Vue Component appeared first on CSS-Tricks.

15:42

Blame the implementation, not the technique

I'm not sure we've gotten much better at this since Tim Kadlec wrote this in 2012:

Stop me if you’ve heard this one before.

“Responsive design is bad for performance.”
“User agent detection is bad. Don’t segment the web.”
“Hybrid apps don’t work as well as native apps.”
“CSS preprocessors shouldn’t be used because they create bloated CSS.”

... Find out for yourself if the tool is really where the blame should be placed.

I'm sure there is some psychological concept that explains why we transfer blame from the offending thing to what we perceive to be the cause.

Sometimes we're good at this. Remember the AMP letter:

The AMP format is not in itself, a problem, but two aspects of its implementation...

Or the fact that accessibility issues aren't React's fault. Pointing at the tools makes it harder to talk about the real problems that need to be resolved.

Sometimes I'm not so good at this. I'm linking to Tim here in an effort to help me remember this.

Direct Link to ArticlePermalink

The post Blame the implementation, not the technique appeared first on CSS-Tricks.

14:30
10 Amazing Web Design Showcases
13:00

What To Do If People Hate Your Brand Mascot

What To Do If People Hate Your Brand Mascot

What To Do If People Hate Your Brand Mascot

Suzanne Scacca
2020-02-17T13:00:00+00:002020-02-17T21:09:30+00:00

There are a number of reasons why businesses decide to use mascots to represent their brands:

  • They want there to be a friendly and reliable face to welcome visitors to the site.
  • They know they need something more than an inventory of products to make an emotional connection with shoppers.
  • They want a strong and recognizable personality that can tie all of their marketing channels together.

While it’s clear that mascots can be invaluable for the business-consumer connection, there’s a very thin line between mascots turning customers into loyal advocates and sending prospects running away in fear.

If you’re struggling to get traction on an existing website and fear the mascot might have something to do with it, this post is for you. You should also keep reading if you’re designing a mascot from-scratch and aren’t sure how to create something your audience will fall in love with.

There’s a very thin line between brand mascots turning customers into loyal advocates and sending prospects running away in fear.

Things You Can Do to Create a Brand Mascot People Love

Not everyone is going to get as lucky as TinyPNG, which has had the same brand mascot for years.

This was the mascot that sat at the top of the page in 2014:

TinyPNG website 2014 A snapshot of the TinyPNG website in 2014 with its panda mascot. (Image source: TinyPNG) (Large preview)

Here it is again in 2017, only it’s a bit brighter and larger in size:

TinyPNG website 2017 A snapshot of the TinyPNG website in 2017 with its panda mascot. (Image source: TinyPNG) (Large preview)

The mascot also started appearing with a crown on the bottom right. This callout encouraged users to subscribe to the Pro tool.

To this day, the website continues to use the mascot in this manner (and with nearly the same layout and content):

TinyPNG website 2020 A snapshot of the TinyPNG website in 2020 with its panda mascot. (Image source: TinyPNG) (Large preview)

The panda mascot works for a number of reasons. It looks very happy, for one. Also, it’s got a welcoming presence, like “Hey, I’m just chilling here, eating my bamboo. Feel free to upload your images whenever.” And it’s downright adorable.

But not every seemingly happy, friendly or cute brand mascot works out this well. Mascots are a subjective thing. It’s like they always say: beauty is in the eye of the beholder.

So, if your audience doesn’t interpret the attractiveness, humor or personality of the mascot as the original creators did, it’s going to be a problem for the business as a whole.

Let’s take a look at what your options are if you suspect that your client’s brand mascot isn’t as adored as they hoped it would be.

Option #1: Modernize It

The first thing to think about is whether or not the mascot is worth salvaging. Is there anything good about the mascot or its personality… or should you start over?

Don’t just go based on your gut. Do some market research and throw some user surveys out there. Maybe message old customers of your client or do a poll on Twitter. You need to know why the mascot isn’t hitting the mark.

Once you’ve nailed down what’s wrong, it’s time to redesign it. Let’s look at some websites that have given their mascots facelifts over the years, starting with HostGator:

HostGator website 2012 A snapshot of the HostGator website from 2012 with its alligator mascot logo and imagery. (Image source: HostGator) (Large preview)

This is what the HostGator website looked like in 2012. The alligator mascot had a heavy presence in the header of the website. His head also appears to be peaking out of the main banner.

Fast forward to 2017 and we see a different side of the HostGator mascot:

HostGator website 2017 A snapshot of the HostGator website from 2017 with its mascot slightly revamped. (Image source: HostGator) (Large preview)

For starters, the alligator in the logo is much smaller, so we can now see the entire body. This gives it a more human-like feeling as opposed to the bottomless gator which more closely resembles a puppet.

The mascot in the main banner is designed the same way it’s always been designed (including the facial expression). However, it’s now donning winter gear for a seasonal touch.

Since then, HostGator has given its mascot a major touchup:

HostGator website 2020 A snapshot of the HostGator website in 2020 with a redesigned alligator mascot. (Image source: HostGator) (Large preview)

Do you know what this redesign looks like to me? It looks like the CGI used in The Irishman.

The Irishman CGI touchup Joe Pesci Vulture magazine shares a side-by-side look at CGI in the movie The Irishman from Netflix. (Image source: HostGator) (Large preview)

I’m not sure if that was the intention behind HostGator’s mascot redesign, but I’m going to assume that there was some user feedback that suggested that a softer and less intimidating mascot would perform better.

Another website that’s given its well-known mascot a touch-up is Chuck E. Cheese.

This was the Chuck E. Cheese website in 2011:

Chuck E. Cheese website 2011 A snapshot of the Chuck E. Cheese website from 2011 with its cartoon mouse mascot (Image source: Chuck E. Cheese) (Large preview)

Not even a decade ago, the Chuck E. Cheese website and its mascot looked like something out of Nickelodeon. Obviously, a design like this would’ve needed an upgrade no matter what considering how much web design has changed.

This is what the website looks like today:

Chuck E. Cheese website 2020 A snapshot of the Chuck E. Cheese website in 2020 without a mascot. (Image source: Chuck E. Cheese) (Large preview)

Gone are the crazy color palette and illustrations. Today, the website is much more subdued and customer-centric.

That said, the mascot pops up from time-to-time. Obviously, though, it’s undergone a much-needed redesign:

Chuck E. Cheese mascot 2020 The Chuck E. Cheese mascot in 2020. (Image source: Chuck E. Cheese) (Large preview)

The new mascot is still a buck-toothed mouse with a welcoming smile and wave. However, it looks more on par with the kinds of animations you’d see coming out of Pixar than old Saturday morning cartoons.

Even if there’s nothing necessarily wrong with the mascot your website is using, it might be worth looking at upgrading it so it better fits with the times as Chuck E. Cheese has done.

Option #2: Change The Tone Of It

Mascots can be really helpful at getting a brand’s message across — over and over again. However, there may be times when the kind of mascot you’ve chosen (or a lack of one) actually stands in the way of the message you’re trying to convey.

Take the old GEICO mascot: the caveman.

GEICO website 2005 - caveman A snapshot of the GEICO website in 2005 when it featured the caveman mascot. (Image source: GEICO) (Large preview)

I don’t know that there was anything wrong with the caveman advertisements. They were smart and funny and were lauded for taking on the subject of political correctness.

That said, GEICO’s customer data must’ve told them that a change-up was needed. Maybe the messaging was too serious or the humor went over some people’s heads.

So, they scrapped the caveman mascot for an animated Cockney-accented gecko:

GEICO website 2020 - gecko A snapshot of the GEICO website in 2020 with its gecko mascot. (Image source: GEICO) (Large preview)

Whereas the cavemen were always offended and storming off whenever someone would say “It’s so easy a caveman could do it”, this anthropomorphic mascot is a much more lighthearted figure in the GEICO landscape. The gecko is always there, ready to provide tips on how to get the most with GEICO.

In other words, it might not be enough to change your mascot to an adorable critter. You might also need to switch up your messaging, too.

While I was writing my last article on mobile storytelling, I did some digging into the alcohol industry. One company, in particular, stood out for its use of a human mascot and storyteller: Aviation Gin.

Now, what I hadn’t covered in that write-up was the fact that Aviation Gin has been around for a while. It was founded in the mid-2000s, long before current co-owner and mascot Ryan Reynolds had anything to do with it.

This was the Aviation Gin website in 2007:

Aviation Gin website 2007 A snapshot of the Aviation Gin website from 2007. (Image source: Aviation Gin) (Large preview)

Granted, these are the early days of the web, so we can’t expect much in the way of design. However, as far as mascots go, there are none to be seen. Unless you count the actual bottle of Aviation Gin.

Nearly 10 years later, Aviation Gin was still rocking the product-centric design:

Aviation Gin website 2016 A snapshot of the Aviation Gin website in 2016. (Image source: Aviation Gin) (Large preview)

It was still very simple in design and the bottle of gin remained the sole focus. Aside from some industry awards, Aviation Gin wasn’t the media darling it is now.

In 2018, Ryan Reynolds bought shares in the company and changed the whole tone of the brand:

Aviation Gin website 2020 A snapshot of the Aviation Gin website in 2020 featuring Ryan Reynolds. (Image source: Aviation Gin) (Large preview)

Today, Ryan Reynolds has become the face of Aviation Gin, pushing it at every turn on his social media. It hasn’t changed the direction of the company itself, but by having a human mascot like Reynolds on its side, the message (and likely the audience, too) has changed.

It’s also opened the brand up to bigger opportunities, like Reynolds’ latest announcement about their partnership with the Westminster Kennel Club Dog Show:

So, if you have a website that performs just “okay” with its audience, a change of tone and pace might be needed. And if you don’t have a mascot yet or one that’s not a good fit, creating one that’s well-designed for a modern-day audience might be exactly what you need.

Option #3: Minimize Its Presence On The Website

Let’s say the mascot’s design and the message it brings with it isn’t the problem. What you suspect is that it’s the amount of space given to it that’s the problem.

This is easy enough to confirm with A/B testing. You’ll just need to study your heatmaps as well as your user personas to come up with some hypotheses about where your mascot should or should not be on the site.

Let’s use Cats Who Code as an example. This was the website back in 2009:

Cats Who Code website 2009 A snapshot of the Cats Who Code website in 2009 with cat logo and imagery. (Image source: Cats Who Code) (Large preview)

Back then, cats were quite prevalent on the site, from the laptop-using cat in the header to the cats in the blog images. What’s more, the tagline of the site “Learn as fast as I catch mice!” made it perfectly clear that the kind of “cats” referred to here wasn’t referring to hip or cool cats. It really was referring to the furry pet.

Skip ahead to 2014 and the cat mascot and tagline has received a makeover:

Cats Who Code website 2014 A snapshot of the Cats Who Code website from 2014 with a new mascot. (Image source: Cats Who Code) (Large preview)

For starters, the mascot has gone from a small tabby to a large black-and-white cat. In addition, the website’s tagline now reads “100% animal-friendly web development blog”. Those are both pretty significant changes.

Now, let’s look at the website in the present day:

Cats Who Code website 2020 A snapshot of the Cats Who Code website in 2020. (Image source: Cats Who Code) (Large preview)

The cat mascot no longer exists in its previous iterations. Now, it’s relegated to a small cat-like icon with code brackets where its face used to be. The website’s cat-friendly messaging is gone, too.

Whether it’s because the cat imagery was distracting or people didn’t like it, this website has undergone a drastic change. Everything is now very buttoned-up.

Another brand that cut back on the appearance of its mascot is Green Giant.

This was the website in 2013:

Green Giant website 2013 A snapshot of the Green Giant website and its mascot in 2013. (Image source: Green Giant) (Large preview)

The jolly green giant mascot is front-and-center on the home page. This is in addition to all the small appearances it makes in every product featured on the site.

In 2016, however, the giant’s likeness was removed from the hero banner and moved up to the logo:

Green Giant website 2016 A snapshot of the Green Giant website in 2016 with the mascot in the logo. (Image source: Green Giant) (Large preview)

It looks like the company was experimenting here, trying to see if moving the mascot’s face to the logo would give them more room to allow their products to shine.

In 2020, though, there’s barely any trace of the mascot left:

Green Giant website 2020 A snapshot of the Green Giant website in 2020. (Image source: Green Giant) (Large preview)

The mascot is gone from the logo as well as the hero image… sort of. It’s subtle, but the mascot’s shadow remains.

The website now appears to be more focused towards sustainability and its mission to contribute to a better world. In that sense, it’s completely justified why the mascot and even the blatant pushing of its products would be moved out of the way.

So, if you feel like your mascot might be getting in the way of getting your point across or perhaps the brand has evolved in a way where a cartoonish figure no longer fits, test out other ways to keep your mascot but in a very lowkey way.

Option #4: Lean Into The Creepiness/Weirdness/Ugliness

One other option you have is to lean into it.

Obviously, you shouldn’t go this route if customers find the mascot to be offensive or boring. If it’s just not working and there’s no way to turn the situation around, just scrap the mascot altogether. You’ll be better off focusing on strengthening your content and building trust that way than to push an already delicate situation.

That said, if you feel like people are reacting negatively to the mascot because of how novel or different it is, then you might want to go crazy with it and see what happens. Before I show you an example of a website that does this, I’m going to show you a real-world example of a sports mascot that turned haters into the biggest of fans.

I was living outside of Philadelphia around the time the Flyers hockey team introduced their new mascot Gritty. It didn’t go over well — at first.

This is how they introduced Gritty:

Philadelphia Flyers Gritty mascot The Philadelphia Flyers introduce their mascot Gritty on Twitter. (Image source: Twitter) (Large preview)

Here are some of the initial responses people had to the creature with the giant beer gut and flaming-orange googly eyes:

@shocks23 speculated about its origins:

Twitter speculation about Gritty mascot Twitter user @shocks23 suspects the Flyers’ mascot has a seedy past. (Image source: Twitter)

@aclee_clips expressed fear:

Twitter user scared of Gritty Twitter user @aclee_clips is horrified by the Philadelphia Flyers’ new mascot. (Image source: Twitter)

And, like so many others, @mirtle was shocked and confused:

Twitter user confused about Gritty mascot Twitter user @mirtle expresses confusion about Philadelphia Flyers’ mascot. (Image source: Twitter)

However, this isn’t a story of a brand mascot that failed.

The city of Philadelphia (along with the rest of the world) eventually fell in love with Gritty after it posed Kim Kardashian-like with a champagne bottle and entered the arena on a wrecking ball Miley Cyrus-style.

Gritty the mascot meme Flyers mascot Gritty gets cheeky by posing with a champagne glass on his bum. (Image source: Twitter)

Over the past couple of years, Gritty has worked very hard to win the hearts of consumers bringing a fun and lighthearted approach to everything it does both on the ice as well as off. And win the hearts it has.

Take, for instance, an incident that happened earlier this year when Gritty was accused of hitting a child at a game. The accusation was investigated and Gritty was cleared of the charges. Through it all, fans had the mascot’s back.

Twitter users love team mascot Gritty Twitter users love Gritty even in the face of scandal. (Image source: (Image source: Twitter)

If you can create a mascot with the right kind of personality, message and purpose, your website and brand will be able to experience this kind of die-hard fandom and support.

That said, this is social media we’re talking about. While the Flyers’ have gone all-in on showing off Gritty in the most awkward of situations or while humorously riffing on pop culture, the website itself only has one page where the mascot appears:

Get to Know Gritty fan page The Get to Know Gritty fan page on the Philadelphia Flyers website. (Image source: Philadelphia Flyers (Large preview)

So, leaning into an awkward/strange/nightmare-inducing mascot might not be right for every site. Here’s one very well-known example where it was the right call:

This is the Mucinex website from 2010:

Mucinex website 2010 A snapshot of the Mucinex website in 2010 featuring its fat, green mucus mascot. (Image source: Mucinex) (Large preview)

If you ask me, this is one of the grossest mascots ever created. It’s literally mucus in human-like form. And yet, it works somehow because it’s done in a humorous manner.

In 2015, Mr. Mucus took on a sweaty and ill-looking appearance:

Mucinex website 2015 A snapshot of the Mucinex website in 2015 with its mucus mascot. (Image source: Mucinex) (Large preview)

This is the only look we get at Mr. Mucus on the website and I’m not sure it worked out very well for the brand. That may be because the mascot resembles Jabba the Hutt instead of a fun-loving mucus ball you want to watch walk down the aisle with Mrs. Mucus.

Nevertheless, the company pushed forward with the mascot, giving it even more airtime. The 2020 version of the website has Mr. Mucus appearing in various states:

Mucinex website 2020 - Mr. Mucus nervous The Mucinex 2020 website shows off Mr. Mucus in different states. This is the mascot nervous about shipping. (Image source: Mucinex) (Large preview)

This looks similar to the Mr. Mucus we saw in 2015. However, something about the messaging in this banner gives his facial expression and clammy skin a different vibe this time around. It says, “Please don’t order this cold medicine. I don’t want to go away!”

In another banner image, we see Mr. Mucus rocking a dad bod alongside a message about working out:

Mucinex website 2020 - Mr. Mucus dad bod The Mucinex 2020 website shows off Mr. Mucus in different states. This is the mascot with its dad bod. (Image source: Mucinex) (Large preview)

The mascot is still pretty gross, but there’s no denying how funny this image is. And then you have this banner that’s targeted at cold remedies for kids:

Mucinex website 2020 - Mr. Mucus kid The Mucinex 2020 website shows off Mr. Mucus in different states. This is the mascot in kid form. (Image source: Mucinex) (Large preview)

I’m not sure if this is supposed to be Mr. Mucus as a kid or the child he had with Mrs. Mucus, but it’s another creative adaptation of the mascot.

According to CBC, Mucinex made a ton of money after launching its Mr. Mucus campaign in 2004, more than doubling its profits. And despite Mr. Mucus being one of the most recognizable mascots, it is also one of the least liked, too.

In this case, being hated was a good thing. Mucinex wanted its customers to be disgusted by Mr. Mucus. The whole purpose of the company is to help people fight off phlegmy throats and stuffed noses.

So, before you throw your hated mascot away, think about where the hate is coming from and if you can make it work to your advantage in another way.

If you can create a mascot with the right kind of personality, message and purpose, your website and brand will be able to experience this kind of die-hard fandom and support.

Wrapping Up

If your website could benefit from a little levity, a mascot would be a fantastic way to draw visitors into the content of your website as well as into the brand’s story. That doesn’t mean that every mascot should draw laughs or be shocking. There are plenty of recognizable and well-loved mascots that have subdued personalities. It’s all about working with the personality of your brand and fitting a mascot to it.

Further Reading on SmashingMag:

Smashing Editorial(ra, il)
11:22
How to Sell Stock Photos
09:00

12 Essential Elements for a Successful Sticker Design

What goes into a designing a successful sticker? More than you might think. A successful sticker design is one that serves the purpose you intended for it, and that purpose isn’t always easy to measure. Stickers can be used for so many things, it could be advertising, product labels, attractive customer freebies – anything.

From the purpose and concept, to the technical details like typography and resolution, here’s each element of sticker design broken down, so you know exactly what to do next.

1.    What is the purpose of your sticker?

Don’t design a sticker without having a clear purpose. For your design to be successful, you need to know what it’s for. Each context may require a different approach.

Let’s say you designed and printed stickers with only your logo on. Even if you follow all the design steps in this guide, it would still just be a sticker with your logo on. Not great if you want to grab attention in a marketing campaign.

As part of your marketing strategy, specify what your stickers will be used for – and where they will be used. You’ll also want an idea of how many stickers you want printing.

Once you’ve figured that out, you’ll know what tips would be most beneficial to use in the design process.

2.    Pick a size that fits your purpose

When you think of stickers, you might think of something small. But these days, you can get stickers printed in almost any size. You could have an entire wall covered with one sticker.

Once you know the purpose of your sticker and where/how you’re going to use it, measure up the area so you know what size you want it to be. You can then set your size in the design software you use, or pass it on to your designer.

The example below is a custom sticker used as a product label. You’d want to know the circumference of the bottles along with the height, and then decide how much vertical space you wanted the label to use.

3.    Choose your shape

You can get your stickers cut in any shape. Stickers are most commonly cut in square and rectangular designs, but this all depends on the purpose of your sticker. Unconventional shapes usually cost more as they require custom cutting.

Concept design

4.    Concept design

In the concept phase, create a rough outline of what you want. Brainstorm some ideas and think of a few designs. You don’t need to be a professional artist in this stage, but it’s essential you have an idea of your design – and, that you’re open to changing it at a later stage. A designer may not always know what angle is best to take at the start, so coming up with an initial concept can help set the tone for the rest of the design process. This is where good old-fashioned pencil and paper comes in handy. Jot down some rough sketches and ideas, then it’s on to the next stage.

5.    Outline

This is where your designer might take over the process. But you can always try your hand at this if you’re tech-savvy. Most artists create a rough sketch of the design in software, then draw back over with well-defined lines.

If you’re looking to make a label quickly, without design knowledge, have a look at Adobe Spark, which is free to use. There’s also Canva, an intuitive browser-based tool. If you want more control over the artistic process, you’ll want a more complete software design package. To make a professional sticker design, you can try one of the following:

Adobe Photoshop

Adobe Illustrator

Inkscape (free)

In the above software programs, you can save the file in vector format, which will allow you to scale the image to any size without the loss of quality. We’ll talk more about what formats are commonly used when it’s time to print.

6.    Pro design

Pro design

If you’re looking for a solid, professional design, hire a professional designer to avoid disappointment. You can always try your hand with one of the free tools above though. Although limited, they sometimes do everything you need, saving you money.

Reach out to other professionals in your network and see who they recommend. Another way to find a pro quickly is to use a freelance marketplace like People Per Hour.

By hiring a pro designer, you’re setting yourself up for a successful sticker design. And of course, you avoid the embarrassment of having a terrible design if you have no idea how to do it yourself.

7.    Typography

Typography is the art and technique of styling and arranging letters so they are appealing and readable, and it’s often overlooked or misunderstood.

Use an attractive, readable font

Don’t sacrifice readability for a fancy font that no one can read. By the same token, don’t make it boring, or commit the sin of using Comic Sans, unless you’re writing for children.

Make your typeface attractive, powerful, and aimed at ‘your crowd’. Choose something that can be seen from a distance. Go with something readable with a bit of character.

Test different font weights

The weight of your font is its thickness. All software allows you to tweak this. Most stickers with writing on use thicker, bold font weights for clarity and impact. But, depending on how much text there is, you might want to vary this between different words or lettering.

Letter arrangement

The way the letters are arranged affects the clarity. The letter arrangement can be anything from the line and letter spacing to the vertical, horizontal, and diagonal positioning of the letters. Once you’re happy with the readability and appearance, you’ve nailed an essential element of sticker design.

8.    Create an impactful message

Create an impactful message

If you’re using words on your sticker, every word matters. With limited space, you must craft a clear and compelling message. This all depends on the purpose of your sticker as mentioned earlier. If you’re offering a promo on a product, make it clear with both the words and typography. If it’s an advertisement, say something simple but appealing – or thought provoking, to get attention.

You could also consider hiring a copywriter to do the writing for you.

Whatever it is you’re trying to say, say it concisely and plainly.

If you’re not using words as a key part of the message, the sticker must at least feature your logo or some way of contacting you. The image must speak for itself, and invoke a sense of curiosity that compels the viewer to investigate further.

9.    Use bright, bold colours

The way you use colours is essential for a successful sticker design. Make them bright and bold so they jump out of the sticker. People like colours that appeal to the senses. Ensure the colours match or complement your other brand marketing material.

There are some great online tools you can use to develop a palette of complementary colours. Take a look at these three:

  • Coolors – automatically generates colour schemes
  • Canva – generates a colour scheme based off your image
  • Paletton – use various methods to fine tune your own colour palette

10. Save it in the right format and size

If you’re sending your stickers off to be printed, or even printing at home, you’ll need to make sure you set the correct resolution and file format. Setting the incorrect resolution, or altering the image size of a file that isn’t a vector, will distort the image and result in a low-quality print. Follow the recommended tips to ensure you get a crisp, high-quality sticker design.

Resolution

Most professional sticker printing companies will have a preference for certain file types, and also a minimum DPI. Images you see online are usually 72DPI, but the standard resolution for printing a sticker is 300DPI, and it can go much higher. Set your DPI to 300, but run this by your sticker design company in the case that they have other options.

Format

You must save your sticker file in either an uncompressed format or a format with lossless compression. Lossless compression means the image file size has been reduced, but the quality remains the same.

Recommended formats: EPS (vector), JPEG, TIFF, PNG, PDF.

11. Print on the right material

Picking a material that suits your design is all part of making a lasting impression on the viewer. Think about what message you’re trying to convey. Are you selling a premium product? Do you want something that will reflect to catch a person’s eye? Have a look at some of the materials you can print on below.

Matte

Matte stickers don’t reflect in the light. This is one good choice if you’re aiming for something premium or sophisticated.

Clear

Transparent vinyl stickers are great if you want a portion of the sticker to be clear.

Gloss

Glossy stickers are a popular choice because they produce a shine that catches the eye. After all, people tend to like shiny things!

Metallic

Polished or brushed metal stickers are also a premium choice, offering a sleek appearance to the viewer.

12.  Set it up correctly for printing

You can’t print professional grade stickers at home without professional equipment. For the best chance at making a successful, high-quality design, consider using a sticker company who have all the right tools.

Bleed, trim, and safe area

The bleed is the excess material outside the trim which will be removed in the final design. The trim is the extra space just outside the safe area, this is the outer region of your printed design. And the safe area is the space within both of these outer areas, which is slightly less than the finished size. You want to create a design that goes beyond the safe area, up to the trim, to avoid unwanted white space in the final design.

These all need to be set up correctly to ensure the design comes out exactly as you imagined it. This is something you should discuss with your sticker design company, as requirements may differ.

Conclusion

As you can see, there’s a lot to take in. The purpose, concept, design, and execution process can seem overwhelming. But it’s not as complicated as you might think, you just have to follow the steps in this guide and employ some of your own creativity. In the process, you’ll learn how to produce a successful sticker design from scratch, which is a great achievement.

You’ll most likely be consulting a sticker design company to print your stickers. Here’s the key information you should run by them:

  • Their preferred file formats
  • What resolution/DPI to save your file
  • What their bleed/trim requirements are

Ultimately, how successful your design is comes down to how much you follow the best practices of marketing, design and other specialist areas.

The post 12 Essential Elements for a Successful Sticker Design appeared first on Line25.

February 16 2020

20:50

Listen to your web pages

A clever idea from Tom Hicks combining MutationObserver (which can "observe" changes to elements like when their attributes, text, or children change) and the Web Audio API for creating sounds. Plop this code into the console on a page where you'd like to listen to essentially any DOM change to hear it doing stuff.

I played with it on my serverless site because it's an SPA so there is plenty of DOM activity as you navigate around.

const audioCtx = new (window.AudioContext || window.webkitAudioContext)()
const observer = new MutationObserver(function(mutationsList) {
  const oscillator = audioCtx.createOscillator()

  oscillator.connect(audioCtx.destination)
  oscillator.type = "sine"
  oscillator.frequency.setValueAtTime(
    Math.log(mutationsList.length + 5) * 880,
    audioCtx.currentTime,
  )

  oscillator.start()
  oscillator.stop(audioCtx.currentTime + 0.01)
})

observer.observe(document, {
  attributes: true,
  childList: true,
  subtree: true,
  characterData: true,
})  

Looks like Tom is experimenting with other audio... what should we call them? Auralizations? Like this sweep-swoop one. There is already a browser extension for it, which includes sounds for network activity happening.

Direct Link to ArticlePermalink

The post Listen to your web pages appeared first on CSS-Tricks.

Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
Could not load more posts
Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
Just a second, loading more posts...
You've reached the end.
(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...