Archive

Archive for the ‘Designing’ Category

Popular Design News of the Week: August 13, 2018 – August 19, 2018

August 19th, 2018 No comments

Every week users submit a lot of interesting stuff on our sister site Webdesigner News, highlighting great content from around the web that can be of interest to web designers.

The best way to keep track of all the great stories and news being posted is simply to check out the Webdesigner News site, however, in case you missed some here’s a quick and useful compilation of the most popular designer news that we curated from the past week.

Note that this is only a very small selection of the links that were posted, so don’t miss out and subscribe to our newsletter and follow the site daily for all the news.

Scroll Bouncing on your Websites

Site Design: Kommigraphics

How Ikea Quietly Tweaks its Design Around the World

Screenlife App – A UI/UX Case Study

Reviewed: New Logo and Identity for Evernote

Fairtrade Website Redesign – A UX Case Study

Why Designers Don’t Want to Think When They Read

A Small Tool to Help You Generate Color Scales in an Instant

Font Flipper — Tinder for Google Fonts

How to Choose a Name for a New Product (with Minimal Stress)

Neede – An Online Design Resource Library

You Can’t Research Without Context

Tini.Es

Study: Blue Light from Screens Can Steadily Blind Us

How to Create a Customer Journey Map [step by Step]

The Design is the Implementation

CanSnippet CE – A CMS for Sharing Code

10,000 Original Copies

HoverSignal – Increase your Website’s Conversions with Notifications

100 Days of Motion Design

Being a Great Designer is About More than Being Great at Design

A Beginner’s Guide to Aspect Ratio

Are Gutenberg’s Bad Reviews a Sign of Failure?

Using Micro-interactions to Enhance Search

How to Launch a Side Project in 10 Days

Want more? No problem! Keep track of top design news from around the web with Webdesigner News.

Add Realistic Chalk and Sketch Lettering Effects with Sketch’it – only $5!

Source

Categories: Designing, Others Tags:

Firefox Multi-Account Containers

August 17th, 2018 No comments

It’s an extension:

Each Container stores cookies separately, so you can log into the same site with different accounts and online trackers can’t easily connect the browsing.

A great idea for a feature if you ask me. For example, I have two Buffer accounts and my solution is to use different browsers entirely to stay logged into both of them. I know plenty of folks that prefer the browser version of apps like Notion, Front, and Twitter, and it’s cool to have a way to log into the same site with multiple accounts if you need to — and without weird trickery.

This is browsers competing on UI/UX features rather than web platform features, which is a good thing. Relevant: Opera Neon and Refresh.

Direct Link to ArticlePermalink

The post Firefox Multi-Account Containers appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

The Fascinating History of the Apple Logo

August 17th, 2018 No comments
Apple Logo

Have you ever wondered what do a bitten apple and technology have in common? The Apple logo has become one of the most iconic and world-wide known logo, but not many people know the history and the meaning of the bitten apple.

The first logo of the company doesn’t look at all like the actual one that represents the Apple brand. The first image of the company has only survived for one year, before Steve Jobs asked the talented artist Rob Janoff to create something more modern and representative for Apple. The finial logo, designed by Ronald Wayne and Steve Jobs, illustrated Sir Isaac Newton under an apple tree, and as background it had a poem written on the side of the drawing. The quotation by Wordsworth that was also inscribed into the logo said: “Newton… a mind forever voyaging through strange seas of thought.”

The Apple Logo: How did it become an iconic image of the company?

The iconic Apple logo, the bitten apple that we can now find it on all the company’s products, was created by Rob Janoff in the 70’s. According to him, the reason Steve Jobs wanted a bitten apple was that people would be able to tell apart the apple from a tomato. You can also look at the bite as a clever play on word. Instead of spelling it B-I-T-E, you can spell it B-Y-T-E as in the measurement for digital storage. It is, of course, a strong reference for a tech company.

The rainbow Apple Logo

The first version the bitten logo was a rainbow stripped apple. This Apple logo represented the company between 1976 and 1998. Rob Janoff explains why Jobs opted for the rainbow in one of his interviews. Once the personal computer Apple II was launched, it was the first computer ever that could display colors on the screen. The representatives of the company wanted to make this fact known by all. Also, the colors were also an attempt to make the logo more accessible, and to attract the young generation.

In 1998, things started to change again, as well as the Apple company’s logo. Steve jobs decided to change it into a monochromatic apple. The rainbow colors of the apple were going to go out of fashion. The new monochromatic logo matched the image of the newest products on the market better than anything else.

Regarding the name of the company, there are many speculations. Unfortunately, there isn’t one most plausible theory among all the existent ones. Some believe that the founders Steve Jobs and Steve Wozniak wanted their start up to appear on the first pages of the phone books. Others believe that they wanted to stand out of the crowd with a simple name, easy to be remembered by. They wanted to create a contrast between their company and all the other hard to remember names of tech companies such as TRS-80, IBM, or Cincom. Also, the idea that the founders wanted to bring a tribute to The Beatles’ record label.

Apple Logo

Read More at The Fascinating History of the Apple Logo

Categories: Designing, Others Tags:

10 WordPress tools & services you need to try (You’re welcome!)

August 17th, 2018 No comments

The WordPress design team set out to build the ultimate website-building platform. That time, they had several things in mind. Among them, they wanted to make building websites as easy as possible. Also, they planned to allow web designers to build exactly what they want down to the finest detail. Users can do so without having to work around restrictions.

It’s an obvious fact that not only did they succeed, they also empowered a lot of web designers. With each new tool or service, web designers are able to build advanced websites.

Take a few minutes to go down this list of 10 top WordPress tools and services. Chances are, you’ll come across a product or service you’ll wish you had to work with a long time ago.

  1. Elementor Page Builder

If you are looking for a powerful web design solution that is also open source and based on WordPress, Elementor is your best choice. With Elementor, you can reach the most astounding results that professional web designers charge a fortune for. It solves most of the limitations imposed on users by the various WordPress themes.

Elementor, with its visual frontend page builder, is the genuine article if you’re looking for a product that enables you to build anything you want down to the minutest of details, without having to write a single line of code. Better yet, this open source page builder is super-fast, it works with any template. Did we mention it costs you nothing to get started?

With Elementor, you can start a page from scratch, use any of its 130+ templates, use your own, or download one from another source.

Elementor’s ranking as the #1 WordPress page builder is entirely justifiable in terms of performance, capabilities, and popularity. With respect to the latter, its user base has grown from a mere handful a little less than 2 years ago to over 1 million users today.

  1. Brizy

Two of Brizy’s top assets are its ease of use and the UX it provides. An additional top asset would have to be that it is free to download and use by anyone having a WordPress website.

Brizy has managed the seemingly impossible in that it provides users with an impressive number of website-building features and options while at the same time presenting them with a user interface that is remarkably free of clutter and distractions. If you need a particular function, setting, or option it’s there when you need it. You don’t have to conduct a search among a host of sidebar items for each and every action you take.

The best way to introduce yourself to Brizy is to test it on their website. The HTML you generate is free and yours to keep and to use however you wish.

  1. Posts Table Pro WordPress Table Plugin

The Posts Table Pro plugin is one you’ll wish you had long ago if your website efforts have included building tabular listings of posts and pages, document libraries, member directories, and the like. This dynamic plugin would have saved you many hours of data entry, which like most manual processes can often be somewhat error-prone.

Now, you can perform the same tasks quickly, error-free, and with the flexibility you need to create tables that exactly meet your requirements. With Posts Table Pro, you can select the pages, posts, custom post types or multimedia items you want to tabulate, order and sort them as you wish, and adjust column parameters, load times, and other characteristics as you deem necessary. Maybe it’s time to start using a tool that lets you build tables your way and do so with relative ease.

Posts Table Pro works with any WordPress theme and comes with expert support from the plugin developers.

  1. WordXpress

Unless you have a very small and simple website to maintain, you might be unaware of the time you spend performing edits and updates, eliminating malware, optimizing plugins, and performing backups. How much is your time worth? Would it be better spent building your business?

The WordXpress team of WordPress maintenance experts will do all of these for you. They will save you time and effort and relieve you of a ton of unnecessary stress, just as they’ve been doing for other website owners for the past decade.

  1. Logic Hop – Personalized Marketing for WordPress

Personalized marketing makes websites much more effective, and Logic Hop is the personalized marketing solution that can help you acquire more leads and generate more sales and conversions than generic marketing solutions are generally capable of. Personalized call-to-actions, for example, convert twice as well as the generic alternatives.

Logic Hop integrates with the tools you’re already using – like Google Analytics – or can collect its own data. All this opens up your WordPress site for personalized marketing and a more effective website.

  1. Goodie

Goodie appeals to small businesses who wish to have their design ideas directly converted into working code without having to go through a middleman. Goodie’s team of experienced developers can completely code your website design for $999. Whether you submit your design in digital file format or sketched out on paper, they’ll work with you to give you precisely the website you want.

  1. Starfish Reviews

Starfish Reviews is a plugin that works with any of the common online reviews platforms to enable you to encourage customer and follower reviews of your business. Having more 5-star reviews on Facebook, iTunes, Google, TripAdvisor, etc. can significantly increase sales since consumers look at and trust online reviews when buying. Ratings also has a positive effect on SEO.

Starfish Reviews sees that positive reviews get published and routes negative reviews back to you as feedback.

  1. Fixmysite.com

Here’s your opportunity to make Fixmysite.com your trusted neighborhood website garage. The Fixmysite.com web mechanics will fix on demand whatever is ailing your website to your complete satisfaction or give you your money back.

The Fixmysite.com team can also help you with web migration, speed optimization, malware removal issues, and provide installation services and perform site audits.

  1. WP Review Pro

Some review styles work better for a given type of product or service than others. WP Review Pro gives you the options

of summarizing reviews as approval percentages, stars ratings, ratios, and thumbs up and down depending upon what has been reviewed. This WooCommerce compatible best review plugin also enables you to generate product and service comparison tables.

  1. WordLift

WordLift is an open source software tool for bloggers, journalists, content marketers, SEO specialists, and web designers. It allows artificial intelligence work for you by translating your website’s articles and pages into machine-friendly content that search crawlers and personal digital assistants use to serve users the right information and help them take action.

This results in a richer and more engaging website UX and a growth of organic traffic.

Conclusion

Have you been looking for ways to build a better website? Or, maybe you’d like to improve a website’s performance, or extend its capabilities? Anyway, there’s something here for you.

More than a few of these tools enable you to add functionality to your websites. It would cost you an arm and a leg to have someone do it for you. Each of these top WordPress products and services is worth is worth its weight in gold.

Read More at 10 WordPress tools & services you need to try (You’re welcome!)

Categories: Designing, Others Tags:

Seriously, though. What is a progressive web app?

August 17th, 2018 No comments

Amberley Romo read a ton about PWAs in order to form her own solid understanding.

“Progressive web app” (PWA) is both a general term for a new philosophy toward building websites and a specific term with an established set of three explicit, testable, baseline requirements.

As a general term, the PWA approach is characterized by striving to satisfy the following set of attributes:

  1. Responsive
  2. Connectivity independent
  3. App-like-interactions
  4. Fresh
  5. Safe
  6. Discoverable
  7. Re-engageable
  8. Installable
  9. Linkable

Direct Link to ArticlePermalink

The post Seriously, though. What is a progressive web app? appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Level up your .filter game

August 17th, 2018 No comments

.filter is a built-in array iteration method that accepts a predicate which is called against each of its values, and returns a subset of all values that return a truthy value.

That is a lot to unpack in one statement! Let’s take a look at that statement piece-by-piece.

  • “Built-in” simply means that it is part of the language—you don’t need to add any libraries to get access to this functionality.
  • “Iteration methods” accept a function that are run against each item of the array. Both .map and .reduce are other examples of iteration methods.
  • A “predicate” is a function that returns a boolean.
  • A “truthy value” is any value that evaluates to true when coerced to a boolean. Almost all values are truthy, with the exceptions of: undefined, null, false, 0, NaN, or "" (empty string).

To see .filter in action, let’s take a look at this array of restaurants.

const restaurants = [
    {
        name: "Dan's Hamburgers",
        price: 'Cheap',
        cuisine: 'Burger',
    },
    {
        name: "Austin's Pizza",
        price: 'Cheap',
        cuisine: 'Pizza',
    },
    {
        name: "Via 313",
        price: 'Moderate',
        cuisine: 'Pizza',
    },
    {
        name: "Bufalina",
        price: 'Expensive',
        cuisine: 'Pizza',
    },
    {
        name: "P. Terry's",
        price: 'Cheap',
        cuisine: 'Burger',
    },
    {
        name: "Hopdoddy",
        price: 'Expensive',
        cuisine: 'Burger',
    },
    {
        name: "Whataburger",
        price: 'Moderate',
        cuisine: 'Burger',
    },
    {
        name: "Chuy's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
    {
        name: "Taquerias Arandina",
        cuisine: 'Tex-Mex',
        price: 'Cheap',
    },
    {
        name: "El Alma",
        cuisine: 'Tex-Mex',
        price: 'Expensive',
    },
    {
        name: "Maudie's",
        cuisine: 'Tex-Mex',
        price: 'Moderate',
    },
];

That’s a lot of information. I’m currently in the mood for a burger, so let’s filter that array down a bit.

const isBurger = ({cuisine}) => cuisine === 'burger';
const burgerJoints = restaurants.filter(isBurger);

isBurger is the predicate, and burgerJoints is a new array which is a subset of restaurants. It is important to note that restaurants remained unchanged from the .filter.

Here is a simple example of two lists being rendered—one of the original restaurants array, and one of the filtered burgerJoints array.

See the Pen .filter – isBurger by Adam Giese (@AdamGiese) on CodePen.

Negating Predicates

For every predicate there is an equal and opposite negated predicate.

A predicate is a function that returns a boolean. Since there are only two possible boolean values, that means it is easy to “flip” the value of a predicate.

A few hours have passed since I’ve eaten my burger, and now I’m hungry again. This time, I want to filter out burgers to try something new. One option is to write a new isNotBurger predicate from scratch.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => cuisine !== 'burger';

However, look at the amount of similarities between the two predicates. This is not very DRY code. Another option is to call the isBurger predicate and flip the result.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = ({cuisine}) => !isBurger(cuisine);

This is better! If the definition of a burger changes, you will only need to change the logic in one place. However, what if we have a number of predicates that we’d like to negate? Since this is something that we’d likely want to do often, it may be a good idea to write a negate function.

const negate = predicate => function() {
  return !predicate.apply(null, arguments);
}

const isBurger = ({cuisine}) => cuisine === 'burger';
const isNotBurger = negate(isBurger);

const isPizza = ({cuisine}) => cuisine === 'pizza';
const isNotPizza = negate(isPizza);

You may have some questions.

What is .apply?

MDN:

apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

What is arguments?

MDN:

The arguments object is a local variable available within all (non-arrow) functions. You can refer to a function’s arguments within the function by using the arguments object.

Why return an old-school function instead of a newer, cooler arrow function?

In this case, returning a traditional function is necessary because the arguments object is only available on traditional functions.

Returning Predicates

As we saw with our negate function, it is easy for a function to return a new function in JavaScript. This can be useful for writing “predicate creators.” For example, let’s look back at our isBurger and isPizza predicates.

const isBurger = ({cuisine}) => cuisine === 'burger';
const isPizza  = ({cuisine}) => cuisine === 'pizza';

These two predicates share the same logic; they only differ in comparisons. So, we can wrap the shared logic in an isCuisine function.

const isCuisine = comparison => ({cuisine}) => cuisine === comparison;
const isBurger  = isCuisine('burger');
const isPizza   = isCuisine('pizza');

This is great! Now, what if we want to start checking the price?

const isPrice = comparison => ({price}) => price === comparison;
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

Now the isCheap and isExpensive are DRY, and isPizza and isBurger are DRY—but isPrice and isCuisine share their logic! Luckily, there are no rules for how many functions deep you can return.

const isKeyEqualToValue = key => value => object => object[key] === value;

// these can be rewritten
const isCuisine = isKeyEqualToValue('cuisine');
const isPrice = isKeyEqualToValue('price');

// these don't need to change
const isBurger = isCuisine('burger');
const isPizza = isCuisine('pizza');
const isCheap = isPrice('cheap');
const isExpensive = isPrice('expensive');

This, to me, is the beauty of arrow functions. In a single line, you can elegantly create a third-order function. isKeyEqualToValue is a function that returns the function isPrice which returns the function isCheap.

See how easy it is to create multiple filtered lists from the original restaurants array?

See the Pen .filter – returning predicates by Adam Giese (@AdamGiese) on CodePen.

Composing Predicates

We can now filter our array by burgers or by a cheap price… but what if you want cheap burgers? One option is to simply chain to filters together.

const cheapBurgers = restaurants.filter(isCheap).filter(isBurger);

Another option is to “compose” the two predicates into a single one.

const isCheapBurger = restaurant => isCheap(restaurant) && isBurger(restaurant);
const isCheapPizza = restaurant => isCheap(restaurant) && isPizza(restaurant);

Look at all of that repeated code. We can definitely wrap this into a new function!

const both = (predicate1, predicate2) => value =>
  predicate1(value) && predicate2(value);

const isCheapBurger = both(isCheap, isBurger);
const isCheapPizza = both(isCheap, isPizza);

const cheapBurgers = restaurants.filter(isCheapBurger);
const cheapPizza = restaurants.filter(isCheapPizza);

What if you are fine with either pizza or burgers?

const either = (predicate1, predicate2) => value =>
  predicate1(value) || predicate2(value);

const isDelicious = either(isBurger, isPizza);
const deliciousFood = restaurants.filter(isDelicious);

This is a step in the right direction, but what if you have more than two foods you’d like to include? This isn’t a very scalable approach. There are two built-in array methods that come in handy here. .every and .some are both predicate methods that also accept predicates. .every checks if each member of an array passes a predicate, while .some checks to see if any member of an array passes a predicate.

const isDelicious = restaurant =>
  [isPizza, isBurger, isBbq].some(predicate => predicate(restaurant));

const isCheapAndDelicious = restaurant =>
  [isDelicious, isCheap].every(predicate => predicate(restaurant));

And, as always, let’s wrap them up into some useful abstraction.

const isEvery = predicates => value =>
  predicates.every(predicate => predicate(value));

const isAny = predicates => value =>
  predicates.some(predicate => predicate(value));

const isDelicious = isAny([isBurger, isPizza, isBbq]);
const isCheapAndDelicious = isEvery([isCheap, isDelicious]);

isEvery and isAny both accept an array of predicates and return a single predicate.

Since all of these predicates are easily created by higher order functions, it isn’t too difficult to create and apply these predicates based on a user’s interaction. Taking all of the lessons we have learned, here is an example of an app that searches restaurants by applying filters based on button clicks.

See the Pen .filter – dynamic filters by Adam Giese (@AdamGiese) on CodePen.

Wrapping up

Filters are an essential part of JavaScript development. Whether you’re sorting out bad data from an API response or responding to user interactions, there are countless times when you would want a subset of an array’s values. I hope this overview helped with ways that you can manipulate predicates to write more readable and maintainable code.

The post Level up your .filter game appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

The Real Problem With Pre-Made Themes

August 17th, 2018 No comments

Designers, developers, site owners… lend me your eyeballs for a bit. There’s something rotten in the state of pre-made website themes. Alright, I’ve offended The Bard quite enough. But you get my point, right? Themes have gotten a bad rap for a variety of reasons: they can have bloated code, content must be designed to fit in them rather than designing them to fit the content, et cetera.

But they’ve also gotten really good. Many are made to be modular, so you only use and load the code you need. People have gotten a lot better at coding things to load fast, and there’s a theme for nearly every conceivable need. So maybe it’s not as optimized as it could be, if you’re not getting Amazon levels of traffic, regular hosting should be fine, right? And again, there’s a theme for every conceivable need! It’s just so convenient.

Wrong, wrong, wrong, (mostly) wrong.

Let me tell you a little story. A long, long time ago in February of 2018, I had an idea. Well, really I had a few ideas of things I desperately wanted to write about, but no one was paying me to do it. And honestly, keeping up a blog on the topics I had in mind wouldn’t be all that feasible. I like my projects to have a beginning, middle, end, and perhaps most importantly, a deadline.

So I thought, hey, why not make some niche/authority sites on these topics so dear to my heart? There’s no reason niche sites have to be predatory glorified ads with terrible aesthetics and UX. I could make them better. And I could just leave them up when I was done, with minimal updates. And hell, I don’t even need to design them! A wiki or knowledge base theme for WordPress or some other CMS would do quite nicely for my purposes.

I found plenty of themes…I very nearly dropped money on

And so I went theme hunting. I found plenty of themes in the categories I had in mind, including some absolutely beautiful premium themes I very nearly dropped money on. That would have been a terrible waste of my cash.

It’s because, you see, each and every one of these themes depended on JavaScript for their most basic functions: displaying any content at all, navigation, and search. (Now I told myself I wasn’t going to get back into this particular crusade. I told myself I could stop writing about how completely depending on JavaScript is a terrible idea. I wasn’t going to do this anymore, darnit!)

But people are getting ripped off, and I can’t stand for that. If you’re selling a theme that depends on JavaScript to work at all, you’re selling a site that is going to break under certain conditions. Whether it’s a slow connection, a plugin incompatibility, some ad network gone rogue, or a random browser hiccup, it’s going to break. If you allow a web product that’s intended for daily use to be that fragile, that’s an accessibility issue, and it’s a rip-off.

It’s one thing to build a JavaScript-dependent site for a client who knows the risks and chooses to take them. It is quite another to sell templates like that, especially without any warning. These things are only sometimes implemented by professional designers or developers who want to save time. They are very often implemented by beginners who are just learning a bit of HTML even as they use your theme.

More than that, these were wiki and knowledge base themes. Those are the kinds of sites people go to when they need help. Customer support and educational sites should be the least likely to break, period. This is a case where both the customer and the user are being let down in a big way.

People will always want flashy stuff, fine. We can’t help that fancy animation grabs the eye, and I don’t blame theme designers for using it as a selling point. But you owe it to your customers to implement fall-backs for every JavaScript element that might break. You owe it to them to at least make your basic layout, navigation, and any forms work under just about any condition. Ancient browsers notwithstanding.

you owe it to your customers to implement fall-backs for every JavaScript element that might break

In my mind, a lack of progressive enhancement, or at least graceful degradation, is the single biggest accessibility nightmare to plague the wonderful world of pre-made sites and themes. Customers are buying these things without knowing exactly what they’re doing, and it’s bound to end in misery. And here I thought bad planning was the biggest problem for theme-based sites.

Yes, implementing fall-backs for everything is difficult, but that’s why you charge money for these things. If they were all that easy to make, they could all be free, right? No, I don’t expect you to code your themes for every version of IE, and yes I realize that most premium themes come with support of some kind or another.

Theme authors just need to recognize that when JavaScript breaks, it most often only breaks for some of the end users, and only some of the time. But those end users could have turned into paying customers for the people who bought the themes, and now they probably won’t. And that’s on us designers and developers, no one else.

Well, now I have to go design my own wiki/knowledge-base style theme (probably for Grav CMS, at this point), because somebody needs to do it right, and it might as well be me. To quote Taylor Swift, “Look what you made me do.”

Add Realistic Chalk and Sketch Lettering Effects with Sketch’it – only $5!

Source

Categories: Designing, Others Tags:

Working with refs in React

August 16th, 2018 No comments

Refs make it possible to access DOM nodes directly within React. This comes in handy in situations where, just as one example, you want to change the child of a component. Let’s say you want to change the value of an element, but without using props or re-rendering the whole component.

That’s the sort of thing refs are good for and what we’ll be digging into in this post.

How to create a ref

createRef() is a new API that shipped with React 16.3. You can create a ref by calling React.createRef() and attaching a React element to it using the ref attribute on the element.

class Example extends React.Component {
  constructor(props) {
    super(props)

    // Create the ref
    this.exampleRef = React.createRef()
  }

  render() {
    return (
      <div>
        // Call the ref with the `ref` attribute
        <input type="text" ref={this.exampleRef} />
      </div>
    )
  }
}

We can “refer” to the node of the ref created in the render method with access to the current attribute of the ref. From the example above, that would be this.exampleRef.current.

Here’s an example:

See the Pen React Ref – createRef by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

class App extends React.Component {
  constructor(props) {
    super(props)
    
    // Create the ref
    this.textInput = React.createRef();
    this.state = {
      value: ''
    }
  }
  
  // Set the state for the ref
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.textInput.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        // This is what will update
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          // Call the ref on <input> so we can use it to update the <h3> value
          <input type="text" ref={this.textInput} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

How a conversation between a child component and an element containing the ref might go down.

This is a component that renders some text, an input field and a button. The ref is created in the constructor and then attached to the input element when it renders. When the button is clicked, the value submitted from the input element (which has the ref attached) is used to update the state of the text (contained in an H3 tag). We make use of this.textInput.current.value to access the value and the new state is then rendered to the screen.

Passing a callback function to ref

React allows you to create a ref by passing a callback function to the ref attribute of a component. Here is how it looks:

<input type="text" ref={element => this.textInput = element} />

The callback is used to store a reference to the DOM node in an instance property. When we want to make use of this reference, we access it using:

this.textInput.value

Let’s see how that looks in the same example we used before.

See the Pen React Ref – Callback Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

class App extends React.Component {
    state = {
    value: ''
  }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.textInput.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - Callback Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <input type="text" ref={element => this.textInput = element} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

When you make use of callback like we did above, React will call the ref callback with the DOM node when the component mounts, when the component un-mounts, it will call it with null.

It is also possible to pass ref from a parent component to a child component using callbacks.

See the Pen React Ref – Callback Ref 2 by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Let’s create our “dumb” component that will render a simple input:

const Input = props => {
  return (
    <div>
      <input type="text" ref={props.inputRef} />
    </div>
  );
};

This component is expecting inputRef props from its parent component which is then used to create a ref to the DOM node.

Here’s the parent component:

class App extends React.Component {
  state = {
    value: ''
  };

  handleSubmit = event => {
    this.setState({ value: this.inputElement.value });
  };

  render() {
    return (
      <div>
        <h1>React Ref - Callback Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <Input inputRef={el => (this.inputElement = el)} />
        <button onClick={this.handleSubmit}>Submit</button>
      </div>
    );
  }
}

In the App component, we want to obtain the text that is entered in the input field (which is in the child component) so we can render it. The ref is created using a callback like we did in the first example of this section. The key lies in how we access the DOM of the input element in the Input component from the App component. If you look closely, we access it using this.inputElement. So, when updating the state of value in the App component, we get the text that was entered in the input field using this.inputElement.value.

The ref attribute as a string

This is the old way of creating a ref and it will likely be removed in a future release because of some issues associated with it. The React team advises against using it, going so far as to label it as “legacy” in the documentation. We’re including it here anyway because there’s a chance you could come across it in a codebase.

See the Pen React Ref – String Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Going back to our example of an input whose value is used to update text value on submit:

class App extends React.Component {
    state = {
    value: ''
  }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.refs.textInput.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - String Ref</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <input type="text" ref="textInput" />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

The component is initialized and we start with a default state value set to an empty string (value=''). The component renders the text and form, as usual and, like before, the H3 text updates its state when the form is submitted with the contents entered in the input field.

We created a ref by setting the ref prop of the input field to textInput. That gives us access to the value of the input in the handleSubmit() method using this.refs.textInput.value.

Forwarding a ref from one component to another

**Ref forwarding is the technique of passing a ref from a component to a child component by making use of the React.forwardRef() method.

See the Pen React Ref – forward Ref by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

Back to our running example of a input field that updates the value of text when submitted:

class App extends React.Component {
    constructor(props) {
      super(props)
      this.inputRef = React.createRef();
      this.state = {
        value: ''
      }
    }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: this.inputRef.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <Input ref={this.inputRef} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

We’ve created the ref in this example with inputRef, which we want to pass to the child component as a ref attribute that we can use to update the state of our text.

const Input = React.forwardRef((props, ref) => (
  <input type="text" ref={ref} />
));

Here is an alternative way to do it by defining the ref outside of the App component:

const Input = React.forwardRef((props, ref) => (
  <input type="text" ref={ref} />
));

const inputRef = React.createRef();

class App extends React.Component {
    constructor(props) {
      super(props)
      
      this.state = {
        value: ''
      }
    }
  
  handleSubmit = e => {
    e.preventDefault();
    this.setState({ value: inputRef.current.value})
  };

  render() {
    return (
      <div>
        <h1>React Ref - createRef</h1>
        <h3>Value: {this.state.value}</h3>
        <form onSubmit={this.handleSubmit}>
          <Input ref={inputRef} />
          <button>Submit</button>
        </form>
      </div>
    );
  }
}

Using ref for form validation

We all know that form validation is super difficult but something React is well-suited for. You know, things like making sure a form cannot be submitted with an empty input value. Or requiring a password with at least six characters. Refs can come in handy for these types of situations.

See the Pen React ref Pen – validation by Kingsley Silas Chijioke (@kinsomicrote) on CodePen.

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

    this.username = React.createRef();
    this.password = React.createRef();
    this.state = {
      errors: []
    };
  }

  handleSubmit = (event) => {
    event.preventDefault();
    const username = this.username.current.value;
    const password = this.password.current.value;
    const errors = this.handleValidation(username, password);

    if (errors.length > 0) {
      this.setState({ errors });
      return;
    }
    // Submit data
  };

  handleValidation = (username, password) => {
    const errors = [];
    // Require username to have a value on submit
    if (username.length === 0) {
      errors.push("Username cannot be empty");
    }
    
    // Require at least six characters for the password
    if (password.length < 6) {
      errors.push("Password should be at least 6 characters long");
    }
    
    // If those conditions are met, then return error messaging
    return errors;
  };

  render() {
    const { errors } = this.state;
    return (
      <div>
        <h1>React Ref Example</h1>
        <form onSubmit={this.handleSubmit}>
          // If requirements are not met, then display errors
          {errors.map(error => <p key={error}>{error}</p>)}
          <div>
            <label>Username:</label>
            // Input for username containing the ref
            <input type="text" ref={this.username} />
          </div>
          <div>
            <label>Password:</label>
            // Input for password containing the ref
            <input type="text" ref={this.password} />
          </div>
          <div>
            <button>Submit</button>
          </div>
        </form>
      </div>
    );
  }
}

We used the createRef() to create refs for the inputs which we then passed as parameters to the validation method. We populate the errors array when either of the input has an error, which we then display to the user.

That’s a ref… er, a wrap!

Hopefully this walkthrough gives you a good understanding of how powerful refs can be. They’re an excellent way to update part of a component without the need to re-render the entire thing. That’s convenient for writing leaner code and getting better performance.

At the same time, it’s worth heeding the advice of the React docs themselves and avoid using ref too much:

Your first inclination may be to use refs to “make things happen” in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to “own” that state is at a higher level in the hierarchy.

Get it? Got it? Good.

The post Working with refs in React appeared first on CSS-Tricks.

Categories: Designing, Others Tags:

Dox Design – A Pet Friendly Design Studio (AOTW#8)

August 16th, 2018 No comments
Dox Design

Out series of articles Agency of the Week becomes more and more diverse with each featured design studio. We enjoy, embrace, and explore diversity as an important part of any design-related process. Dox Design is an unusual studio, and today, we are making them known by all the animal lovers out there!

When you own a relatively new pet company, it comes with many challenges. We ourselves know how hard any start might be, but when you’re determined, there’s no turning back. A good time management, great services provided, and amazing marketing, you can make it to the tops in no-time. Now, believe or not, your website, your business card, and your brand’s identity are the best marketers ever. It doesn’t matter how much money you invest in publicity, sponsored posts, and ads, as long as your business’s image is repulsive.

OK, maybe I exaggerated a little bit. It only takes a few small flaws of your website, and your potential clients will find another dog hairdresser. But do not fear! Dox Design specializes in your type of passion, and promises to create “compelling designs for pet businesses.” Dox Design understands that any design goes beyond a pretty picture of a cat with a bow, and focuses on how your client can best relate to your services. Nobody said that creating an emotional bound with your clients is a piece of cake. Dox Design does it with so much talent, that it doesn’t look like rocket science, either.

If you don’t believe be, I invite you to take a look at some of the studios pieces of work.

Paws On Pine

Dox Design

Emotion loaded photos will always be a go-to when it comes to a business you want people to relate to.

Golden Wellness Dogs

Dox Design

Even if you are a medicine related company, you don’t want to scare your clients off with cruel images. When the animal feels happy, the owner feels happy. Also, pay close attention to the colors you choose.

Puppy Paws Coffee

Dox Design

How many people enjoy a cup of coffee while walking a dog? Countless. Again, make yourself relevant.

Another great example that proves that design and emotion go hand in hand.

Beans & Bones

Dox Design

Clean design means more than overwhelming design. Allow your clients to “breath,” don’t suffocate them with information.

The Michigan-based design studio proves with every fulfilled mission that they are a trust-worthy, dedicated, and amazingly talented team.

Whether it is a beautifully crafted logo or a well thought-out website, we put your customer at the core of what we do. Every color we choose, every screen flow we map out has a rhyme and a reason. We get it, and our designs will help your customers get it too.

We at Webdesignledger have been closely following Dox Design’s work and came to the conclusion that they are one of the top studios for pet companies that need to become a brand. Don’t hesitate to contact them and meet the amazing designers Kaila Piepkow and Jordan Piepkow.

Hoping that this blog post has reached the right people, we invite other unusual design studios to write us at webdesignledger.blog@gmail.com, for a feature on our blog. Also, visit us daily for more snippets of inspiration, resource, and creativity.

Read More at Dox Design – A Pet Friendly Design Studio (AOTW#8)

Categories: Designing, Others Tags:

Building Battleship in CSS

August 16th, 2018 No comments

This is an experiment to see how far into an interactive experience I can get using only CSS. What better project to attempt than a game? Battleship seemed like a good challenge and a step up from the CSS games I’ve seen so far because it has the complexity of multiple areas that have to interact with two players.

Wanna see the complete game?

View Repo View Demo

Oh, you wanna learn how it works? Let’s dig in.

I could tell right away there was going to be a lot of repetitive HTML and very long CSS selectors coming, so I set up Pug to compile HTML and Less to compile CSS. This is what all the code from here on is going to be written in.

Interactive elements in CSS

In order to get the game mechanics working, we need some interactive elements. We’re going to walk through each one.

HTML checkboxes and :checked

Battleship involves a lot of checking to see whether a field contains a ship or not, so we’re going to use a boatload of checkboxes.

[type*='checkbox'] {
  // inactive style

  &:checked {
    // active style
  }
}

To style checkboxes, we would first need to reset them using appearance: none; which is only poorly supported right now and needs browser prefixes. The better solution here is to add helper elements. tags can’t have children, including pseudo elements (even though Chrome will render them anyway), so we need to work around that using the adjacent sibling selector.

[type*='checkbox'] {
  position: relative;
  opacity: none;

  + .check-helper {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: none;
    // further inactive styles
  }

  &:checked {
    + .check-helper {
      // active styles
    }
  }
}

If you use a for the helper element, you will also extend the click area of the checkbox onto the helper, allowing you to position it more freely. Also, you can use multiple labels for the same checkbox. Multiple checkboxes for the same label are not supported, however, since you would have to assign the same ID for each checkbox.

Targets

We’re making a local multiplayer game, so we need to hide one player’s battlefield from the other and we need a pause mode allowing for a player to switch without glancing at the other player’s ships. A start screen explaining the rules would also be nice.

HTML already gives us the option to link to a given ID in the document. Using :target we can select the element that we just jumped to. That allows us to create an Single Page Application-like behavior in a completely static document (and without even breaking the back button).

- var screens = ['screen1', 'screen2', 'screen3'];
body
  nav
    each screen in screens
      a(href='#' + screen)

  each screen in screens
    .screen(id=screen)
      p #{screen}
.screen {
  display: none;

  &:target {
    display: block;
  }
}

Visibility and pointer events

Rendering elements inactive is usually done by using pointer-events: none; The cool thing about pointer-events is that you can reverse it on the child elements. That will leave only the selected child clickable, but the parent stays click-through. This will come in handy later in combination with checkbox helper elements.

The same goes for visibility: hidden; While display: none; and opacity: 0; make the element and all it’s children disappear, visibility can be reversed.

Note that a hidden visibility also disables any pointer events, unlike opacity: 0;, but stays in the document flow, unlike display: none;.

.foo {
  display: none; // invisible and unclickable
  .bar {
    display: block; // invisible and unclickable
  }
}

.foo {
  visibility: hidden; // invisible and unclickable
  .bar {
    visibility: visible; // visible and clickable
  }
}

.foo {
  opacity: 0;
  pointer-evens: none; // invisible and unclickable
  .bar {
    opacity: 1;
    pointer-events: all; // still invisible, but clickable
  }
}
CSS Rule Reversible opacity Reversible pointer events
display: none; ? ?
visibility: hidden; ? ?
opacity: 0;
pointer-events: none;
? ?

OK, now that we’ve established the strategy for our interactive elements, let’s turn to the setup of the game itself.

Setting up

We have some global static variables and the size of our battlefields to define before we actually start:

@gridSize: 12;
@zSea: 1;
@zShips: 1000;
@zAbove: 2000;
@seaColor: #123;
@enemyColor: #f0a;
@playerColor: #0c8;
@hitColor: #f27;

body {
  --grid-measurements: 70vw;
  @media (min-aspect-ratio: 1/2) {
    --grid-measurements: 35vh;
  }
}

The grid size is the size of the battlefield: 12×12 fields in this case. Next, we define some z-indexes and colors.

Here’s the Pug skeleton:

doctype html

head
  title Ships!
  link(rel="stylesheet", href="style.css")
  meta(charset="UTF-8")
  meta(name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no")
  meta(name="theme-color" content="#000000")

body

Everything HTML from this point on will be in the body.

Implementing the states

We need to build the states for Player 1, Player 2, pause, and a start screen. We’ll do this like it was explained above with target selectors. Here’s a little sketch of what we’re trying to achieve:

We have a few modes, each in its own container with an ID. Only one mode is to be displayed in the viewport—the others are hidden via display: none;, except for player modes. If one player is active, the other needs to be outside of the viewport, but still have pointer events so the players can interact with each other.

.mode#pause

each party in ['p1', 'p2']
  .mode(id=party)

.mode#start

.status
  each party  in ['p1', 'p2']
    a.player-link.switch(href='#' + party)
  a.status-link.playpause(href='#pause') End Turn

h1
  Ships!

The .status div contains the main navigation. Its entries will change depending on the active mode, so in order to select it properly, we’ll need put it after our .mode elements. The same goes for the

, so it ends up at the end of the document (don’t tell the SEO people).

.mode {
  opacity: 0;
  pointer-events: none;

  &:target,
  &#start {
    opacity: 1;
    pointer-events: all;
    z-index: 1;
  }

  &#p1, &#p2 {
    position: absolute;
    transform: translateX(0);
    opacity: 1;
    z-index: 2;
  }

  &#p1:target {
    transform: translateX(50vw);

    +#p2 {
      transform: translateX(50vw);
      z-index: 2;
    }
  }

  &#p2 {
    transform: translateX(50vw);
    z-index: 1;
  }

&#pause:target {
    ~ #p1, ~ #p2 {
      opacity: 0;
    }
  }
}

#start {
  .mode:target ~ & {
    display: none;
  }
}

The .mode div never has pointer events and always is fully transparent (read: inactive), except for the start screen, which is enabled by default and the currently targeted screen. I don’t simply set it to display: none; because I still need it to be in the document flow. Hiding the visibility won’t work because I need to activate pointer events individually later on, when hitting enemy ships.

I need #p1 and #p2 to be next to each other because that’s what’s going to enable the interaction between one players hits and the other players ships.

Implementing the battlefields

We need two sets of two battlefields for a total of four battlefields. Each set contains one battlefield for the current player and another for the opposite player. One set is going to be in #p1 and the other one in #p2. Only one of the players will be in the viewport, but both retain their pointer events and their flow in the document. Here’s a little sketch:

Now we need lots of HTML. Each player needs two battlefields, which need to have 12×12 fields. That’s 576 fields in total, so we’re going to loop around a bit.

The fields are going to have their own class declaring their position in the grid. Also, fields in the first row or line get a position indicator, so you get to say something cool like “Fire at C6.”

each party in 'p1', 'p2']
  .mode(id=party)
    each faction in 'enemy', 'player']
      .battlefield(class=faction, class=party)
        each line in 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
          each col, colI in 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L']
            div(class='field-x' + (colI+1) + '-y' + line)
              if (col === 'A')
                .indicator-col #{line}
              if (line === 1)
                .indicator-line #{col}

The battlefield itself is going to be set in a CSS grid, with its template and measurements coming from the variables we set before. We’ll position them absolutely within our .mode divs and switch the enemy position with the player. In the actual board game, you have your own ships on the bottom as well. Note that we need to escape the calc on the top value, or Less will try to calculate it for you and fail.

.battlefield {
  position: absolute;
  display: grid;
  grid-template-columns: repeat(@gridSize, 1fr);
  width: var(--grid-measurements);
  height: var(--grid-measurements);
  margin: 0 auto 5vw;
  border: 2px solid;
  transform: translate(-50%, 0);
  z-index: @zSea;

  &.player {
    top: calc(var(--grid-measurements) ~"+" 150px);
    border-color: transparent;

    :target & {
      border-color: @playerColor;
    }
  }

  &.enemy {
    top: 100px;
    border-color: transparent;

    :target & {
      border-color: @enemyColor;
    }
  }
}

We want the tiles of the battlefield to be a nice checkerboard pattern. I wrote a mixin to calculate the colors, and since I like my mixins separated from the rest, this is going into a components.less file.

.checkerboard(@counter) when (@counter > 0) {
  .checkerboard(@counter - 2);

  &[class^='field-'][class$='-y@{counter}'] {
    &:nth-of-type(odd) {
      background-color: transparent;

      :target & {
      background-color: darken(@seaColor, 3%);
    }
  }

  &:nth-of-type(even) {
    background-color: transparent;

    :target & {
        background-color: darken(@seaColor, 4%);
      }
    }
  }
}

When we call it with .checkerboard(@gridSize);, it will iterate through every second line of the grid and set background colors for odd and even instances of the current element. We can color the remaining fields with an ordinary :odd and :even.

Next, we place the indicators outside of the battlefields.

[class^='field-'] {
  position: relative;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  height: 100%;
  background-color: transparent;
  
  .checkerboard(@gridSize);
  :target &:nth-of-type(even) {
    background-color: darken(@seaColor, 2%);
  }

  :target &:nth-of-type(odd) {
    background-color: darken(@seaColor, 1%);
  }

  [class^='indicator-'] {
    display: none;

    :target & {
      position: absolute;
      display: flex;
      justify-content: center;
      width: calc(var(--grid-measurements)~"/"@gridSize);
      height: calc(var(--grid-measurements)~"/"@gridSize);
      color: lighten(@seaColor, 10%);
      pointer-events: none;
    }

    &.indicator-line {
      top: -1.5em;
      align-items: flex-start;
    }

    &.indicator-col {
      left: -2.3em;
      align-items: center;
    }
  }
}

Implementing the ships

Let’s get to the tricky part and place some ships. Those need to be clickable and interactive, so they’re going to be checkboxes. Actually, we need two checkboxes for one ship: miss and hit.

  • Miss is the bottom one. If nothing else is on that field, your shot hits the water and triggers a miss-animation. The exception is when a player clicks on their own battlefield. In that case, the ship animation plays.
  • When an own ships spawns, it activates a new checkbox. This one is called hit. It’s placed at the exact same coordinates as its corresponding ship, but in the other players attack field and above the checkbox helper for the miss. If a hit is activated, it displays a hit animation on the current player’s attack field as well as well as on the opponent’s own ship.

This is why we need to position our battlefields absolutely next to each other. We need them aligned at all times in order to let them interact with each other.

First, we’re going to set some styles that apply to both checkboxes. We still need the pointer events, but want to visually hide the checkbox and work with helper elements instead.

.check {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  
  + .check-helper {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
  }
}

We’ll also write some classes for our events for later use right now. This will also go into components.less:

.hit-obj {
  position: absolute;
  visibility: visible;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  animation: hit 1s forwards;
}

.ship-obj {
  position: absolute;
  left: 0;
  top: 0;
  width: 90%;
  height: 90%;
  border-radius: 15%;
  animation: setShip 0.5s forwards;
}

.miss-obj {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border-radius: 50%;
  animation: miss 1s forwards;
}

Spawning and missing ships

Those two events are basically the same. If you hit the sea in your own battlefield, you create a ship. If you hit the sea in the enemy battlefield, you trigger a miss. That happens by calling the respective class from our components.less file within a pseudo element of the helper class. We use pseudo elements here because we need to place two objects in one helper later on.

If you spawn a ship, you shouldn’t be able to un-spawn it, so we make it lose its pointer events after being checked. However, the next hit-checkbox gains it pointer events, enabling the enemy to hit spawned ships.

.check {
  &.ship {
    &:checked {
      pointer-events: none;
    }

    &:checked + .check-helper {
      :target .player & {
        &::after {
          content: "";
          .ship-obj; // set own ship
        }
      }

      :target .enemy & {
        &::after {
          content: "";
          .miss-obj; // miss enemy ship
        }
      }
    }        

    &:checked ~ .hit {
      pointer-events: all;
    }
  }
}

Hitting ships

That new hit checkbox is positioned absolutely on top of the other player’s attack field. For Player 1 that means by 50vw to the right and by the grid height + 50px margin to the top. It has no pointer events by default, they are going to be overwritten by those set in .ship:check ~ .hit, so only ships that are actually set, can be hit.

To display a hit event, we need two pseudo elements: one that confirms the hit on the attack field; and one that shows the victim where they have been hit. :checked + .check-helper::after calls a .hit-obj from components.less onto the attacker’s field and the corresponding ::before pseudo element gets translated back to the victim’s own battlefield.

Since the display of hit events isn’t scoped to the active player, we need to remove all unnecessary instances manually using display: none;.

.check {
  &.hit {
    position: absolute;
    top: ~"calc(-1 * (var(--grid-measurements) + 50px))";
    left: 50vw;
    width: 100%;
    height: 100%;
    pointer-events: none;

    #p2 &,
    #p1:target & {
      left: 0;
    }

    #p1:not(:target) & + .check-helper::before {
      left: 50vw;
    }

    &:checked {
      opacity: 1;
      visibility: hidden;
      pointer-events: none;

      + .check-helper {
        &::before {
          content: "";
          .hit-obj; // hit enemy ships
          top: ~"calc(-1 * (var(--grid-measurements) + 50px))";
      }

        &::after {
          content: "";
          .hit-obj; // hit own ships
          top: -2px;
          left: -2px;
        }

        #p1:target &::before,
        #p1:target ~ #p2 &::after,
        #p1:not(:target) &::after,
        #p2:target &::before {
          display: none;
        }
      }
    }

    #p1:target .battlefield.p1 &,
    #p2:target .battlefield.p2 & {
      display: none;
    }
  }
}

Animating the events

While we did style our miss, ship and hit objects, there’s nothing to be seen yet. That’s because we are still missing the animations making those objects visible. Those are simple keyframe animations that I put into a new Less file called animations.less.

@keyframes setShip {
  0% {
    transform: scale(0, 0);
    background-color: transparent;
  }

  100% {
    transform: scale(1, 1);
    background-color: @playerColor;
  }
}

@keyframes hit {
  0% {
    transform: scale(0, 0);
    opacity: 0;
    background-color: transparent;
  }

  10% {
    transform: scale(1.2, 1.2);
    opacity: 1;
    background-color: spin(@hitColor, 40);
    box-shadow: 0 0 0 0.5em var(--shadowColor);
  }

  100% {
    transform: scale(.7, .7);
    opacity: .7;
    background-color: @hitColor;
    box-shadow: 0 0 0 0.5em var(--shadowColor);
  }
}

@keyframes miss {
  0% {
    transform: scale(0, 0);
    opacity: 1;
    background-color: lighten(@seaColor, 50);
  }

  100% {
    transform: scale(1, 1);
    opacity: .8;
    background-color: lighten(@seaColor, 10);
  }
}

Add customizable player names

This isn’t really necessary for functionality, but it’s a nice little extra. Instead of being called “Player 1” and “Player 2,” you can enter your own name. We do this by adding two to .status, one for each player. They have placeholders in case the players don’t want to enter their names and want to skip to the game right away.

.status
  input(type="text" placeholder="1st Player").player-name#name1
  input(type="text" placeholder="2nd Player").player-name#name2
  each party  in ['p1', 'p2']
      a.player-link.switch(href='#' + party)
  a.status-link.playpause(href='#pause') End Turn

Because we put them into .status, we can display them on every screen. On the start screen, we leave them as normal input fields, for the players to enter their names. We style their placeholders to look like the actual text input, so it doesn’t really matter if players enter their names or not.

.status {
  .player-name {
    position: relative;
    padding: 3px;
    border: 1px solid @enemyColor;
    background: transparent;
    color: @playerColor;

    &::placeholder {
      color: @playerColor;
      opacity: 1; // Reset Firefox user agent styles
    }
  }
}

On the other screens, we remove their typical input field styles as well as their pointer events, making they appear as normal, non-changeable text. .status also contains empty links to select players. We style those links to have actual measurements and display the name inputs without pointer events above them. Clicking a name triggers the link now, targeting the corresponding mode.

.status {
  .mode#pause:target ~ & {
    top: 40vh;
    width: calc(100% ~"-" 40px);
    padding: 0 20px;
    text-align: center;
    z-index: @zAbove;

    .player-name,
    .player-link {
      position: absolute;
      display: block;
      width: 80%;
      max-width: 500px;
      height: 40px;
      margin: 0;
      padding: 0;

      &:nth-of-type(even) {
        top: 60px;
      }
    }

    .player-name {
      border: 0;
      text-align: center;
      pointer-events: none;
    }
  }
}

The player screens only need to display the active player, so we remove the other one.

.status {
  .mode#p1:target ~ & #name2 {
    display: none;
  }
  
  .mode#p2:target ~ & #name1 {
    display: none;
  }
}

Some notes on the Internet Explorer and Edge: Microsoft browsers haven’t implemented the ::placeholder pseudo element. While they do support :-ms-input-placeholder for IE and ::-ms-input-placeholder, as well as the webkit-prefix for Edge, those prefixes only work if ::placeholder is not set. As far as I played around with placeholders, I only managed to style them properly in either the Microsoft browsers, or all the other ones. If someone else has a workaround, please share it!

Putting it all together

What we have so far is a functional, but not very handsome game. I use the start screen to clarify some basic rules. Since we don’t have a hard-coded win condition and nothing to prevent players to place their ships wildly all over the place, I created a “Play fair” note that encourages the good ol’ honor system.

.mode#start
  .battlefield.enemy
    ol
      li
        span You are this color.
      li
        span Your enemy is
        span this
        span color
      li
        span You may place your ships as follows:
        ul
          li 1 x 5 blocks
          li 2 x 4 blocks
          li 3 x 3 blocks
          li 4 x 2 blocks

I’m not going into the detail of how I went about getting things exactly to my liking since most of that is very basic CSS. You can go through the end result to pick them out.

When we finally connect all the pieces, we get this:

See the Pen CSS Game: Battleships by Daniel Schulz (@iamschulz) on CodePen.

Wrapping up

Let’s look back at what we’ve accomplished.

HTML and CSS may not be programming languages, but they are mighty tools in their own domain. We can manage states with pseudo classes and manipulate the DOM with pseudo elements.

While most of us use :hover and :focus all the time, :checked goes by largely unnoticed, only for styling actual checkboxes and radio buttons at best. Checkboxes are handy little tools that can help us to get rid of unnecessary JavaScript in our more simple front end features. I wouldn’t hesitate to build dropdown or off-canvas menus in pure CSS in real life projects, as long as the requirements don’t get too complicated.

I’d be a bit more cautious when using the :target selector. Since it uses the URL hash value, it’s only usable for a global value. I think I’d use it for, say, highlighting the current paragraph on a content page, but not for reusable elements like a slider or an accordion menu. It can also quickly get messy on larger projects, especially when other parts of it start controlling the hash value.

Building the game was a learning experience for me, dealing with pseudo selectors interacting with each other and playing around with lots of pointer events. If I had to build it again, I’d surely choose another path, which is a good outcome for me. I definitely don’t see it as a production-ready or even clean solution, and those super specific selectors are a nightmare to maintain, but it has some good parts in it that I can transition to real life projects.

Most importantly though, it was a fun thing to do.

The post Building Battleship in CSS appeared first on CSS-Tricks.

Categories: Designing, Others Tags: